基类虚拟析构函数 - 五法则?

问题描述 投票:0回答:1

我有一个带有虚拟默认析构函数的基

State
接口类。

class State {
public:
    virtual void event() = 0;

    virtual ~State() = default; // relevant part

    virtual void onCreate() {}
    virtual void onDestroy() {}
    virtual void onActivate() {}
    virtual void onDeactivate() {}
};

然后是一些继承它的类:

class GameState : public State {
public:
    void event() override;
    // ...
};

class MenuState : public State {
public:
    void event() override;
    // ...
};
如果没有复制操作或用户定义了“析构函数”,则编译器会生成默认的移动操作。 如果用户没有定义移动操作,编译器会生成默认的复制操作。

通过声明虚拟默认析构函数我已经有效地删除了默认移动操作,我是否正确?
  1. 如果基类隐式删除了其移动操作,并且基类只是一个没有数据成员的接口,那么移动操作是否适用于派生类?
  2. 这里遵循5法则真的明智吗?显式删除或默认所有 5 个特殊成员函数似乎相当臃肿。
假设您的基类具有复制(并且可能移动)构造函数和赋值运算符。在这种情况下你会期待什么?
c++ state move virtual-destructor rule-of-five
1个回答
0
投票
MenuState menuState; State state = menuState; // be aware that this State object is not a MenuState any more

如果你的
State
类是抽象的(例如

onActivate()

 是纯虚拟的),上面的方法就没有任何意义,因为 
State
 实例是不允许的。
但即使没有,当您将任何 
MenuState

成员放入

State

 对象时,它们也会被切片。如果基类的实例本身没有多大意义,则应该删除复制和移动构造函数以及赋值运算符。
对于派生(具体)类,复制或移动可能更有意义。在这种情况下,在基类中拥有 
protected

复制构造函数和赋值运算符会很有用。因此,您无法实例化基类本身,但您的派生类可以使用它。

MenuState menuState;
MenuState copy = menuState; // might be useful

但是,此类层次结构通常与指针一起使用(如
std::unique_ptr

std::shared_ptr

)。那么 
virtual
 
clone()
 方法有时会更有用。
auto state = std::make_unique<MenuState>();
std::unique_ptr<State> copy = state->clone();

在内部,这个
clone()
方法可能会使用复制构造函数,它可以是

public

 (如果你的派生类不是 
final
,请小心切片)或 
protected
 (如果你想确保只有使用
clone()
方法)。

© www.soinside.com 2019 - 2024. All rights reserved.