复制、移动、交换、赋值和析构函数的C++继承?我需要哪个

C++ Inheritance of copy, move, swap, assignment and destructor? Which do I need

本文关键字:继承 交换 移动 赋值 复制 析构函数 C++      更新时间:2023-10-16

假设我有两个类

Base管理一些内存。它具有工作移动、交换、赋值和析构函数。Derived不会添加任何需要管理的新内容(没有新的内存分配)。

class Base
{
public:
    Base();
    Base(const Base& other);
    friend void swap(Base& a, Base& b);
    Base(Base&& other);
protected:
    int** some2Darray;
    int w, h;
};
class Derived : public Base
{
public:
    Derived();
    //...?
};

我需要在派生类中实现所有这些函数吗?如何重用基类中的那些函数?在这节课上我不需要管理更多的内存了。

如果我将成员添加到派生类中,这些函数会是什么样子?我应该完全重写所有这些函数吗?或者有没有办法使用例如"复制"基类,并在复制构造函数中额外复制一个添加的成员?

c++11以来,您可以继承(编辑:是的,这不是真正的继承,也许应该明确指出)构造函数。通过

class Derived : public Base
{
public:
    Derived();
    using Base::Base; // <-- this will import constructors
};

但这不会照顾到任何额外的东西!

但是,您不需要复制代码。您可以直接调用父函数。

例如:

class Derived : public Base
{
   int extra;
public:
   Derived() : Base(), extra(42){};
   Derived(const Derived& other) : Base(other) {extra = other.extra;};
   void copy(const Derived& other);
   friend void swap(Derived& a, Derived& b);
};
void Derived::copy(const Derived& other){
   Base::copy(other);
   extra = other.extra;
}

另外,不要忘记虚拟析构函数。

编辑:对于交换,我只需要将派生实例强制转换为它们的基,使编译器使用为父类型定义的交换。然后交换多余的东西。

void swap(Derived& a, Derived& b){
    swap(static_cast<Base&>(a), static_cast<Base&>(b));
    swap(a.extra, b.extra);
}

首先:构造函数、赋值运算符和析构函数是而不是继承的(*)。相反,在某些情况下,编译器可能会自动为您合成

那么,什么时候需要写它们呢?仅当default生成的版本不符合您的需求时:

  • 可访问性不是你想要的(它总是public
  • 方法应为deleted
  • default行为不正确(例如,浅拷贝)
  • 编译器无法为您合成该方法

关于后两点:

  • 三规则规定,如果您编写复制构造函数、复制赋值运算符或析构函数中的任何一个;你也应该提供另外两个
  • 在C++11中,如果您编写这3种特殊方法中的任何一种,那么Move构造函数和Move赋值运算符都不会自动合成
  • 在C++11中,如果您编写了Move构造函数或Move赋值运算符,那么这三种特殊方法都不会自动合成

(*)C++11名为继承构造函数的功能命名错误,它更像是委派而不是传承


也就是说,如果Derived没有任何棘手的属性,那么您可能可以避免编写这些成员。如果您仍然希望编写它们(例如,为了避免内联),您应该能够使用= default语法:

// Derived.h
class Derived: public Base {
public:
    Derived(Derived const&) = default;
    Derived& operator(Derived const&);
};
// Derived.cpp
Derived& Derived::operator=(Derived const&) = default;

我不确定move操作符,但您不必实现copy ctor、destructor和copy操作符,因为标准函数会自动从所有基类中调用相应的函数。

编辑:另请参阅如何使用基类';C++中的构造函数和赋值运算符?