将派生类标记为可移动而基类不可移动是否有意义\适合吗?

Joh*_*ohn 5 c++ constructor copy-constructor move-constructor c++11

将派生类标记为可移动而基类不可移动是否有意义\适合吗?

我知道这种不一致在 C++ 中是合法的,但它在实践中有意义\适合吗?

一般来说,我应该刻意保持这种一致性吗?

这种情况怎么样:当我打算将派生类标记为不可移动和不可复制时,我是否也应该将基类标记为不可移动和不可复制?

我做了几次测试才清楚。

这是第一个例子。由于基类是不可复制和不可移动的,因此派生类实际上是不可移动的,因为它有一个移动构造函数,这在我的期望中。提示:下面的代码片段无法编译。

#include <memory>
#include <string>
#include <iostream>

class Base {
public:
    Base(){}
    Base(const Base&) = delete;
    Base(Base&&)      = delete;
    Base& operator=(const Base&) = delete;
    Base& operator=(Base&&) = delete;
};

class Derived:public Base
{
public:
    Derived(){}
    Derived(const Derived&) = default;
    Derived(Derived&&)      = default;
    Derived& operator=(const Derived&) = default;
    Derived& operator=(Derived&&) = default;
};

int main()
{
    Derived derived;

    Derived derived1{std::move(derived)};
}
Run Code Online (Sandbox Code Playgroud)

这是第二个例子。基类是可复制且不可移动的,但派生类实际上是可移动的,因为在调用派生类的移动构造函数时,它会调用基类的复制构造函数,而不是基类的移动构造函数,即也在我的预料之中。提示:下面的代码片段效果很好。

#include <memory>
#include <string>
#include <iostream>

class Base {
public:
    Base(){}
    Base(const Base&) = default;
    Base(Base&&)      = delete;
    Base& operator=(const Base&) = default;
    Base& operator=(Base&&) = delete;
};

class Derived:public Base
{
public:
    Derived(){}
    Derived(const Derived&) = default;
    Derived(Derived&&)      = default;
    Derived& operator=(const Derived&) = default;
    Derived& operator=(Derived&&) = default;
};

int main()
{
    Derived derived;

    Derived derived1{std::move(derived)};
}

Run Code Online (Sandbox Code Playgroud)

更新

感谢@Nightlord,他发现上面的代码片段不能用 编译Clang,这确实出乎我的意料。

小智 1

我知道这种不一致在 C++ 中是合法的,但是在实践中有意义吗?

一般来说,我应该刻意保持这种一致性吗?

是的,我认为你应该保持一致性。要使派生类可移动而基类不可移动,基类不能持有任何数据成员,否则移动未完成。

如果您的类不包含任何数据成员,您可能会将其用作接口。移动构造函数不适用于这种情况,因为客户端仅识别接口(基类)而不是具体类(派生类)。