从具有用户声明的 dtor 和移动支持的抽象基础派生

Deriving from an abstract base with a user-declared dtor and move-support

用户声明的 dtor 阻止 move-ctor/-assignment-operator 的自动生成, 但是自动生成是否只会在定义了 dtor 的 class 中被阻止,或者自动生成是否也会在所有派生的 class 中被阻止?我问这个,因为我正在使用许多纯虚拟 classes,它们都提供用户声明的 dtor。我是否必须现在升级所有这些 classes 以获得移动支持,或者它仍然可以开箱即用吗?

这是我的场景当前的示例:

struct BigData {};

struct BaseA
{
    virtual void func() = 0;
    virtual ~BaseA() = default;
};

struct A : public BaseA
{
    BigData _data;
    void func() override {}
};

现在,我必须使用以下哪些变体来 可以肯定的是,移动将像下面那样使用 例如?

A a;
std::vector< A > va;
va.push_back( std::move( a ) ); //Should really use move instead of copy

变体 1:仅升级基础 class

struct BaseA
{
    virtual void func() = 0;
    virtual ~BaseA() = default;

    BaseA() = default;
    BaseA(BaseA&&) = default;
    BaseA& operator=(BaseA&&) = default;
    BaseA(const BaseA&) = default;
    BaseA& operator=(const BaseA&) = default;
};

struct A : public BaseA
{
    BigData _data;
    void func() override {}
};

变体 2:仅升级派生 class

struct BaseA
{
    virtual void func() = 0;
    virtual ~BaseA() = default;
};

struct A : public BaseA
{
    BigData _data;
    void func() override {}
    A() = default;
    A(A&&) = default;
    A& operator=(A&&) = default;
    A(const A&) = default;
    A& operator=(const A&) = default;
};

变体 3:升级基础 class 和派生 class

struct BaseA
{
    virtual void func() = 0;
    virtual ~BaseA() = default;

    BaseA() = default;
    BaseA(BaseA&&) = default;
    BaseA& operator=(BaseA&&) = default;
    BaseA(const BaseA&) = default;
    BaseA& operator=(const BaseA&) = default;
};

struct A : public BaseA
{
    BigData _data;
    void func() override {}
    A() = default;
    A(A&&) = default;
    A& operator=(A&&) = default;
    A(const A&) = default;
    A& operator=(const A&) = default;
};

变体 4:无事可做

在基础中没有移动构造函数与在基础中有删除的移动构造函数是两回事。

首先,派生的 classes 仍然可以遵循零规则并具有由编译器创建的 默认生成 移动构造函数。

对于后者,默认的走法也会在派生中被删除。

如果您的 class 中有用户定义的析构函数(或用户定义的复制构造函数,或用户定义的复制赋值运算符),则不提供默认移动操作,但不会隐式删除它们。因此,如果派生 class 遵循拥有它们的规则,则它仍然有权进行默认移动操作,而无需将它们显式声明为 =default.

Cpp 参考 says:

The implicitly-declared or defaulted move constructor for class T is defined as deleted if any of the following is true:

... T has direct or virtual base class that cannot be moved (has deleted, inaccessible, or ambiguous move constructors); ...

请注意,让用户声明析构函数不会使 class 不可移动,它只是没有默认生成的移动。