【问题标题】:Is it necessary to create a Copy Constructor for derived classes?是否有必要为派生类创建复制构造函数?
【发布时间】:2019-05-31 16:25:35
【问题描述】:

如果我有一个具有复杂数据成员的基类,比如说char*,并且在我的继承链的末尾我有另一个具有相同类型 DM 的类,我是否必须实现所有的 CCTOR其他课程在路上?

例如:

动物类:

class Animal
{
    int age;
    char* name;
    Animal() { ... } 
    Animal(const Animal &animal) { ..deep copying name..}
}

哺乳动物类:

class Mammal : public Animal
{
    int height;
    Mammal() { ... } 
}

马类:

class Horse : public Mammal 
{
    char* color;
    Horse() { ... } 
    Horse(const Horse &horse ) { ..deep copying color..}
}

我是否需要在 Mammal 中实现 CCTOR,即使它只有一个 int 作为数据成员?

基本上我的问题是:复制复杂对象(由多个类构建)时,编译器是否分别激活每个部分的 CCTOR?

编辑: 需要明确的是,我想复制一个 Horse 对象。如果我按照上面的方式编写代码,它的名称也会被深度复制吗?

【问题讨论】:

  • 除非您自己指定,否则复制构造函数将由编译器生成。
  • 如果您使用std::string 而不是char*,则无需为任何类编写复制构造函数。
  • 尝试使用 Horse(const Horse& horse): Mammal(horse) {...}
  • 而且您不需要为哺乳动物实施单独的 CCTOR。在这种情况下,默认值会完成它需要做的所有工作。

标签: c++ oop copy-constructor


【解决方案1】:

不,你没有。默认情况下(如 Mammal),复制构造函数将调用每个基类的复制构造函数(按顺序),然​​后调用每个成员变量的复制构造函数(按顺序)。因此,哺乳动物的复制构造函数很好。

请注意我关于“每个成员变量的复制构造函数”的观点。当然,char* 的复制构造函数什么都不做——但是如果你用合适的复制构造函数将 char* 包装在一个类中,那么 AnimalHorse 都可以使用该类作为它们的成员变量——并且不会需要自己的拷贝构造函数。

当然,std::string 已经为您提供了(但我假设您实际上有更复杂的情况)。

【讨论】:

    【解决方案2】:

    我是否需要在 Mammal 中实现 CCTOR,即使它只有一个 int 作为数据成员?

    没有。

    复制复杂对象(由多个类构建)时,编译器是否分别激活每个部分的 CCTOR?

    是的。

    参见例如https://en.cppreference.com/w/cpp/language/copy_constructor#Implicitly-defined_copy_constructor:

    对于非联合类类型(classstruct),构造函数按其初始化顺序执行对象基类和非静态成员的完整成员复制,使用直接初始化。

    (强调我的。)

    这就像基础对象只是类的另一个成员。如果Animal 像正确的值类型一样工作(具有执行正确操作的复制构造函数、赋值运算符和析构函数),则您不必在派生类中执行任何特殊操作,例如Mammal


    但是请注意,现代 C++ 风格努力将成员管理排除在构造函数之外。也就是说,例如Horse 不应该关心在其构造函数(和析构函数)中为 color 分配(和解除分配)内存。

    相反,每个成员都应自行管理(您必须将 color 的类型更改为其他类型,例如 std::string),因此编译器生成的默认复制构造函数和析构函数可以正常工作。

    【讨论】:

      【解决方案3】:

      您有问题的类成员是char* 原始指针。

      在惯用的 c++ 中,您可以改用 std::string 来解决该问题,因此您无需指定任何构造函数:

      class Animal
      {
          int age;
          std::string name;
          Animal() = default; // not really neccessary, just for demonstration
                              // purpose
          Animal(const Animal &animal) = default; // not really neccessary, just for
                                                  // demonstration purpose
      };
      

      class Mammal : public Animal
      {
          int height;
      };
      

      class Horse : public Mammal 
      {
          std::string color;
      };
      

      【讨论】:

      • 我知道,这只是为了举例。我想了解背后的逻辑。
      • @Daniel 如果您想要一份副本,您需要确保所有内容都深度复制。基类构造函数需要从初始化列表中显式调用。
      猜你喜欢
      • 2020-03-08
      • 1970-01-01
      • 2013-08-21
      • 1970-01-01
      • 2016-12-30
      • 2011-02-24
      • 1970-01-01
      • 2019-08-07
      • 1970-01-01
      相关资源
      最近更新 更多