简体   繁体   English

具有用户定义的类成员的类的复制构造函数

[英]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.

相关问题 工会会员有用户定义的构造函数 - Member of Union has User-Defined Constructor 用户定义的类的构造函数不使用向量 - Constructor of user-defined class not working with vector 用户定义的函数作为传递给cpp类构造函数的参数 - user-defined function as a parameter passed to cpp class constructor 是否有必要为具有另一个类 B 的数据成员的类 A 重载赋值运算符和复制构造函数? - Is it necessary to overload the assignment operator and the copy constructor for a class A which has a data member of another class B? 类对象的复制列表初始化是用户定义的转换吗 - Is the copy-list-initialization for class object a user-defined conversion 复制带有指向用户定义类型的指针的类的构造函数 - copy constructor for a class with pointer to a user defined type 在用户定义的复制构造函数中使用隐式复制构造函数 - Use of the Implicit Copy Constructor in User-Defined Copy Constructor 复制具有C ++中没有默认构造函数的成员的类的构造函数 - Copy constructor for class that has member without default constructor in C++ 如何为具有std :: stringstream成员的类编写复制构造函数? - How do I write a copy constructor for my class which has a std::stringstream member? 具有std :: atomic成员变量的类的复制构造函数/赋值运算符出错 - Error with copy constructor/assignment operator for a class which has std::atomic member variable
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM