[英]copy constructor of a class which has an user-defined class member
I'm reading thinking in c++ chapter 14 : "Functions that don't automatically inherit"我正在阅读 C++ 第 14 章中的思考:“不会自动继承的函数”
class GameBoard {
public:
GameBoard() { cout << "GameBoard()\n"; }
GameBoard(const GameBoard&) {
cout << "GameBoard(const GameBoard&)\n";
}
GameBoard& operator=(const GameBoard&) {
cout << "GameBoard::operator=()\n";
return *this;
}
~GameBoard() { cout << "~GameBoard()\n"; }
};
class Game {
GameBoard gb; // Composition
public:
// Default GameBoard constructor called:
Game() { cout << "Game()\n"; }
// You must explicitly call the GameBoard
// copy-constructor or the default constructor
// is automatically called instead:
Game(const Game& g) : gb(g.gb) {
//Game(const Game& g) {
cout << "Game(const Game&)\n";
}
Game(int) { cout << "Game(int)\n"; }
Game& operator=(const Game& g) {
// You must explicitly call the GameBoard
// assignment operator or no assignment at
// all happens for gb!
gb = g.gb;
cout << "Game::operator=()\n";
return *this;
}
class Other {}; // Nested class
// Automatic type conversion:
operator Other() const {
cout << "Game::operator Other()\n";
return Other();
}
~Game() { cout << "~Game()\n"; }
};
In the above code, I'm confused by the copy constructor and assignment constructor of Game
class:在上面的代码中,我被Game
类的复制构造函数和赋值构造函数弄糊涂了:
// You must explicitly call the GameBoard
// copy-constructor or the default constructor
// is automatically called instead:
Game(const Game& g) : gb(g.gb) {
//Game(const Game& g) {
cout << "Game(const Game&)\n";
}
Game& operator=(const Game& g) {
// You must explicitly call the GameBoard
// assignment operator or no assignment at
// all happens for gb!
gb = g.gb;
cout << "Game::operator=()\n";
return *this;
}
The author gives the comment: " You must explicitly call the GameBoard
copy-constructor or the default constructor is automatically called instead: " Why if I don't explicitly call the GameBoard
copy-constructor, then the default constructor will be called?作者给出评论:“你必须显式调用GameBoard
复制构造函数,否则会自动调用默认构造函数: ”为什么如果我不显式调用GameBoard
复制构造函数,则会调用默认构造函数?
And for the assignment constructor, if I don't explicitly call the GameBoard
assignment operator, then no assignment happens.对于赋值构造函数,如果我没有显式调用GameBoard
赋值运算符,则不会发生赋值。 Why?为什么?
Why if I don't explicitly call the GameBoard copy-constructor, then the default constructor will be called?为什么如果我没有显式调用 GameBoard 复制构造函数,那么会调用默认构造函数?
If you hadn't written any explicit copy-constructor for Game
, then the compiler would generate one for you that copy-constructs gb
.如果您没有为Game
编写任何显式的复制构造函数,那么编译器将为您生成一个复制构造gb
的函数。 On the other hand, in the moment you explicitly define your own copy constructor, the compiler thinks "Ok, this guy really knows what he's doing, so let's give him full control " .另一方面,在您明确定义自己的复制构造函数的那一刻,编译器会认为“好吧,这家伙真的知道他在做什么,所以让我们完全控制他吧” 。
By gaining full control, you also have the responsibility of explicitly specifying exactly all the actions that you want to be taken during your copy construction.通过获得完全控制权,您还有责任明确指定在复制构建期间要执行的所有操作。 If you do not specify any actions, then the compiler must assume that the default mechanism for constructing objects shall be adopted.如果您不指定任何操作,则编译器必须假定应采用构造对象的默认机制。 And the default mechanism for constructing objects is to invoke the default constructor .而构造对象的默认机制是调用默认构造函数。
Since you seem to know what you're doing, the compiler won't make any assumptions on the correct construction procedure for your member variables.由于您似乎知道自己在做什么,因此编译器不会对您的成员变量的正确构造过程做出任何假设。 You wanted full control, now you have it: forgot something?您想要完全控制,现在您拥有它:忘记了什么? You get default construction.您将获得默认构造。
if I don't explicitly call the GameBoard assignment operator, then no assignment happens.如果我没有明确调用 GameBoard 赋值运算符,则不会发生赋值。 Why?为什么?
The answer is pretty similar.答案非常相似。 By explicitly defining your own operator =
, you are telling the compiler that you want to take full control over the way your objects are assigned.通过显式定义自己的operator =
,您就是在告诉编译器您希望完全控制对象的分配方式。 The compiler won't try to get on your way by making assumptions that might not be correct.编译器不会通过做出可能不正确的假设来尝试继续前进。 Instead, it will just set aside and leave you all the decision power.相反,它只会搁置一旁,留给你所有的决策权。
On the other hand, suppose the compiler silently generated the assignment gb = g.gb
, but for some (hopefully good) reason you didn't want that assignment to be performed: how would you tell the compiler not to perform it, if the default behavior were to generate such an instruction?另一方面,假设编译器默默地生成了赋值gb = g.gb
,但是由于某些(希望是好的)原因,您不希望执行该赋值:如果默认行为是生成这样的指令?
Besides, unless it is really needed, it is a good programming practice to let the compiler generate implicitly a copy/move constructor, destructor, and a copy/move assignment operator for your class: for more information, see this article by R. Martinho Fernandes on the so-called Rule of Zero .此外,除非确实需要,否则让编译器为您的类隐式生成复制/移动构造函数、析构函数和复制/移动赋值运算符是一种很好的编程习惯:有关更多信息,请参阅 R. Martinho 的这篇文章费尔南德斯关于所谓的零规则。
Hope this helped clarifying.希望这有助于澄清。
These comments don't really make sense to me.这些评论对我来说真的没有意义。
If you simplify the code to something like this:如果您将代码简化为以下内容:
#include <iostream>
using namespace std;
class GameBoard {
public:
GameBoard() { cout << "GameBoard()\n"; }
GameBoard(const GameBoard&) {
cout << "GameBoard(const GameBoard&)\n";
}
GameBoard& operator=(const GameBoard&) {
cout << "GameBoard::operator=()\n";
return *this;
}
~GameBoard() { cout << "~GameBoard()\n"; }
};
class Game {
GameBoard gb; // Composition
};
int main() {
cout << "Default Constructing Game object\n";
Game g;
cout << "\nCopy constructing Game object\n";
Game h = g; // uses copy ctor
cout << "\nDefault constructing another Game object\n";
Game i;
cout << "\nAssigning a Game object\n";
i = g; // uses assignment operator.
return 0;
}
You will (or should, anyway) get output like this:您将(或无论如何应该)得到如下输出:
Default Constructing Game object
GameBoard()
Copy constructing Game object
GameBoard(const GameBoard&)
Default constructing another Game object
GameBoard()
Assigning a Game object
GameBoard::operator=()
~GameBoard()
~GameBoard()
~GameBoard()
Maybe he's talking about the fact that what happens by default will not happen by default when you define your own constructor/assignment operator.也许他在谈论这样一个事实,即当您定义自己的构造函数/赋值运算符时,默认情况下不会发生默认情况。 If so, that's true (and maybe we're confused for the same reason: because this seems to be belaboring the exceptionally obvious).如果是这样,那是真的(也许我们出于同样的原因感到困惑:因为这似乎是在为异常明显的事情而苦恼)。
When you customize the copy constructor and or assignment operator, you have to handle all of your member variables.当您自定义复制构造函数和/或赋值运算符时,您必须处理所有成员变量。
When you do not code the copy constructor and/or assignment operator, default ones are generate by the compiler.当您不对复制构造函数和/或赋值运算符进行编码时,编译器会生成默认值。 Be aware that the defaults do shallow assignments and copies.请注意,默认值执行浅分配和复制。 Both just go through each member variables and use their assignment operators or copy constructors.两者都只是遍历每个成员变量并使用它们的赋值运算符或复制构造函数。
// NOTE don't you strdup or free in c++ (see new, delete and the string class)
// this is for BAD example only
class Stuff {
public:
char * thing;
Stuff( void ) : thing(0) {}
~Stuff() { if( thing ) free thing; };
void copyThing( char * other ) { thing = strdup(other); }
}
class Other {
public:
Stuff myStuff;
}
void BadExample() {
Other oa;
oa.copyThing( "Junk" );
Other ob;
ob = oa; // will work but oa and ob myStuff.thing will point to the same address
// and you will attempt to free it twice during deconstruction
}
class BetterStuff {
public:
char * thing;
BetterStuff( void ) : thing(0) {}
~BetterStuff() { if( thing ) free thing; };
void copyThing( char * other ) { thing = strdup(other); }
BetterStuff & operator = ( const BetterStuff & rhs ) {
if( rhs.thing ) thing = strdup( rhs.thing );
}
}
class BetterOther {
public:
BetterStuff myStuff;
}
void Example() {
BetterOther oa;
oa.copyThing( "Junk" );
BetterOther ob;
ob = oa; // now ob has a private copy of the string and can free it.
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.