具有用户定义的类成员的类的复制构造函数
copy constructor of a class which has an user-defined class member
我正在阅读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"; }
};
在上面的代码中,我被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;
}
作者给出了评论:"您必须显式调用GameBoard
复制构造函数,否则会自动调用默认构造函数:"为什么如果我不显式调用GameBoard
复制构造函数,那么会调用默认构造函数?
对于赋值构造函数,如果我没有显式调用GameBoard
赋值运算符,那么就不会发生赋值为什么?
为什么如果我没有显式调用GameBoard副本构造函数,那么会调用默认构造函数?
如果您没有为Game
编写任何显式复制构造函数,那么编译器将为您生成一个复制构造gb
的构造函数。另一方面,当您明确定义自己的复制构造函数时,编译器会认为"好吧,这家伙真的知道自己在做什么,所以让我们让他完全控制"。
通过获得完全控制权,您还有责任明确指定在副本构建过程中要执行的所有操作。如果没有指定任何操作,那么编译器必须假设应采用构造对象的默认机制。构造对象的默认机制是调用默认构造函数。
由于您似乎知道自己在做什么,编译器不会对成员变量的正确构造过程做出任何假设。你想要完全控制,现在你有了:忘了什么?您将获得默认构造。
如果我没有明确调用GameBoard赋值操作符,那么就不会发生赋值。为什么?
答案很相似。通过显式定义自己的operator =
,您告诉编译器您希望完全控制对象的分配方式。编译器不会试图通过做出可能不正确的假设来阻碍你。相反,它只会搁置一边,留给你所有的决定权。
另一方面,假设编译器无声地生成了赋值gb = g.gb
,但出于某种(希望是好的)原因,您不希望执行该赋值:如果默认行为是生成这样的指令,您将如何告诉编译器不要执行它?
此外,除非真的需要,否则让编译器为类隐式生成复制/移动构造函数、析构函数和复制/移动赋值运算符是一种很好的编程实践:有关更多信息,请参阅R.Martinho Fernandes关于所谓的零规则的文章
希望这有助于澄清。
这些评论对我来说真的没有意义。
如果你把代码简化为这样的东西:
#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 objectn";
Game g;
cout << "nCopy constructing Game objectn";
Game h = g; // uses copy ctor
cout << "nDefault constructing another Game objectn";
Game i;
cout << "nAssigning a Game objectn";
i = g; // uses assignment operator.
return 0;
}
你会(或者应该,无论如何)得到这样的输出:
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()
也许他说的是,当你定义自己的构造函数/赋值运算符时,默认情况下发生的事情将而不是。如果是这样的话,那就是真的(也许我们也因为同样的原因感到困惑:因为这似乎过于明显了)。
自定义复制构造函数和/或赋值运算符时,必须处理所有成员变量。
当您不编写复制构造函数和/或赋值运算符的代码时,默认的由编译器生成。请注意,默认值执行浅层分配和复制。两者都只是遍历每个成员变量,并使用它们的赋值运算符或复制构造函数。
// 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.
}
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 继承:构造函数,初始化C++11中基类的类C数组成员
- C++-我可以创建另一个类的成员并在构造函数中使用它吗
- 如果基类包含双指针成员,则派生类的构造函数
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- constexpr构造函数需要常量成员函数时出现问题
- 如何在c++中定义以struct为数据成员的类中的构造函数
- 在作为静态成员包含在另一个类中的类的构造函数中使用 cout
- 在成员构造函数之后调用基类构造函数
- C++:如何在对象构造过程中调用初始值设定项列表之外的成员构造函数
- 用作成员构造函数参数的函数的求值顺序
- 从成员构造函数(Brace Initializer vs Initializer列表)抛出异常
- 不正确的成员构造函数定义
- 我可以基于模板参数将某个值传递给成员构造函数吗
- 在类定义中调用成员构造函数
- 使用已删除的副本构造函数和初始值设定项列表重载调用类定义中的成员构造函数
- 正在从成员构造函数调用虚拟函数
- c++初始化类成员构造函数
- c++模板限制成员构造函数