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
)
方法应该是delete
d
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++复制、移动、交换、赋值和析构函数的继承?我需要哪个的主要内容,如果未能解决你的问题,请参考以下文章
为啥这个核心转储错误发生在我的课堂上?我已经包含了复制构造函数、复制赋值和析构函数