C++应该重写派生类中的复制构造函数吗

C++ Should I overwrite copy constructor in derived class

本文关键字:复制 构造函数 重写 派生 C++      更新时间:2023-10-16

我有一个带有自定义复制构造函数的基类,它负责处理分配的内存。我也从那个基地开始上课。该派生类没有对内存做任何其他操作。

复制构造函数在dervied类中应该是什么样子?覆盖交换、移动和分配如何?

除了swap,您不应该做任何其他事情。在这方面,基类就像一个数据成员,编译器生成的复制构造函数和赋值(以及移动(如果适用))包括它

swap不同,因为没有编译器生成的swap,只有命名空间std中的默认实现,然后是程序员为用户定义的类型定义的任何专门化或ADL重载。

因此,如果已经有一个函数看起来像:

namespace foo {
    void swap(Base &lhs, Base &rhs) {
        lhs.swap(rhs); // or maybe the gory details are in this function
    }
}

你什么都不做,有些用户称之为:

foo::swap(derived1, derived2);

然后基础部件将被交换,而派生部件不会,这非常糟糕。

用户不应该这样调用swap,但你知道用户是什么样的。如果BaseDerived在同一个命名空间中,并且他们只是假设它们都能工作,那么用户可能会觉得这特别有吸引力。因此,如果您认为您的用户(或您自己的代码库)在调用swap的方式上没有原则,您可能需要确保Derived有过载以阻止它们。

用户应调用swap,如:

using std::swap;
swap(base1, base2);
swap(derived1, derived2);

当与Base一起使用时,它将调用foo::swap,而当与Derived一起调用时,它会调用std::swapstd::swap<Derived>可能效率低下(如果Base为了效率而实现了交换,那么Derived也应该如此)。因此,出于这个原因,您可能也想为Derived实现swap,但速度慢并没有错那么糟糕。

也就是说,你在问动作。如果CCD_ 19是可有效移动的,那么CCD_。也许它可以改进,也许不能,但它应该是边缘的,因为三步很难被击败。

您和用户还应该意识到,swap不能很好地处理多态性(因为通常情况下,两个对象必须具有相同的完整类型才能进行交换),并且为基类实现它可能会带来麻烦。

Derived d1, d2;
Base &b1 = &d1, &b2 = d2;
swap(b1, d2); // swaps just the base part
swap(b1, b2); // swaps just the base part

因此,首先,用户需要知道不要这样调用swap。其次,您可能需要考虑带有swapBase作为基类是否真的设计良好。

有一个所谓的五规则(以前的三规则),它说如果你有用户定义的任何一个:

  • 复制构造函数
  • 移动构造函数
  • 析构函数
  • 复制分配运算符
  • 移动分配运算符

您可能还希望用户定义其他四个。


另一方面,有一条零规则:您可以使用自动处理这些事情的资源对象(RAII),而不是定义这五个特殊的成员函数。

这样的对象是数据成员还是某个类C的基类(子对象)并不重要:隐式声明的&编译器提供的C的已定义特殊成员函数将调用该资源对象的特殊成员函数,这很可能就足够了。

提示:对于特定的示例,可以给出更精确的答案

不能"覆盖"构造函数。它不是C++词汇表中的一个术语。您可以覆盖函数,但前提是它是虚拟的。

通常,您不应该在任何正确编写的基类的子类的构造函数中做任何特殊的事情。让每一代人都照顾好自己。