是否有必要为派生类创建复制构造函数?

Is it necessary to create a Copy Constructor for derived classes?

提问人:Daniel 提问时间:6/1/2019 最后编辑:Guy AvrahamDaniel 更新时间:11/6/2023 访问量:1620

问:

如果我有一个具有复杂数据成员的基类,比方说,在我的继承链的末尾,我有另一个具有相同类型 DM 的类,我是否必须实现所有其他类的 CCTOR(复制构造函数)?char*

例如:

动物类:

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..}
}

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

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

编辑: 为了清楚起见,我想复制一个对象。如果我按上面的方式编写代码,它的名字也会被深度复制吗?Horse

C++ OOP 复制构造函数

评论

0赞 πάντα ῥεῖ 6/1/2019
除非您指定自己的,否则编译器将生成复制构造函数。
5赞 NathanOliver 6/1/2019
如果使用 instead of ,则无需为任何类编写复制构造函数。std::stringchar*
0赞 Lehks 6/1/2019
尝试使用 Horse(const Horse& horse): Mammal(horse) {...}
0赞 Lehks 6/1/2019
而且您不需要为 Mammal 实施单独的 CCTOR。在这种情况下,默认的会完成它需要执行的所有工作。

答:

3赞 melpomene 6/1/2019 #1

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

不。

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

是的。

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

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

(强调我的。

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


但请注意,现代 C++ 样式努力将成员管理排除在构造函数之外。也就是说,例如 不应关注在其构造函数(和析构函数)中分配(和取消分配)内存。Horsecolor

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

4赞 Martin Bonner supports Monica 6/1/2019 #2

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

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

事实上,当然,已经为您提供了(但我认为您在现实中有一个更复杂的情况)。std::string

0赞 πάντα ῥεῖ 6/1/2019 #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;
};

评论

0赞 Daniel 6/1/2019
我知道,这只是一个例子。我想了解背后的逻辑。
0赞 πάντα ῥεῖ 6/1/2019
@Daniel 如果你想有一个副本,你需要确保所有内容都是深度复制的。基类构造函数需要从初始值设定项列表中显式调用。