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

Posted

技术标签:

【中文标题】C++复制、移动、交换、赋值和析构函数的继承?我需要哪个【英文标题】:C++ Inheritance of copy, move, swap, assignment and destructor? Which do I need 【发布时间】:2014-01-02 20:48:35 【问题描述】:

假设我有两个班级

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();
    //...?
;

我是否需要在派生类中实现所有这些功能才能让它变得更好?如何重用基类中的这些功能?我不需要在这个类中管理更多内存。

如果我将成员添加到 Derived 类,这些函数会是什么样子?我应该完全重写所有这些函数还是有一些方法可以使用例如“复制”基类并在复制构造函数中额外复制一个添加的成员?

【问题讨论】:

一定要继承,组合不行吗?如果您只想让Derived 能够访问由Base 管理的资源,您只需将Base 成员添加到Derived 这看起来很经典XY question 【参考方案1】:

我不确定移动运算符,但您不必实现复制 ctor、析构函数和复制运算符,因为标准函数会自动从所有基类调用相应的函数。

编辑:另见How to use base class's constructors and assignment operator in C++?

【讨论】:

【参考方案2】:

你可以继承(编辑:是的,这不是真正的继承,也许这应该明确指出)构造函数自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);

【讨论】:

谢谢。这就是我要找的。还有一件事。如果派生中没有任何额外成员,我是否必须声明复制构造函数?或者我可以相信编译器从基类调用一个? 再提一个问题,我会接受的。派生类中的交换函数呢?我有交换功能作为朋友功能。如何复用base中的swap函数? @Hooch 好的。我一开始误解了,所以我不得不删除我的评论。再次首先抱歉没有回答第一个问题,但在我回答之前,Matthieu 的回答已经详细介绍了。我编辑了答案。我认为这应该可行。【参考方案3】:

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

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

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

关于后两点:

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

(*) 名为继承构造函数的 C++11 特性名不副实,它比继承更具委派。 p>


话虽如此,如果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;

【讨论】:

那么 Derived(Derived const&) = default;会从 Base 调用复制构造函数吗? @Hooch: 是的,以及Derived 的每个其他基础和属性的复制构造函数,按照它们的声明顺序。

以上是关于C++复制、移动、交换、赋值和析构函数的继承?我需要哪个的主要内容,如果未能解决你的问题,请参考以下文章

C++ 堆栈分配的对象赋值和析构函数调用

c++ 复制构造函数和析构函数

为啥这个核心转储错误发生在我的课堂上?我已经包含了复制构造函数、复制赋值和析构函数

c++中的构造函数和析构函数

C++在单继承多继承虚继承时,构造函数复制构造函数赋值操作符析构函数的执行顺序和执行内容

C++ 继承中构造和析构对象(面试题可能问)