Reputation: 856
I have a base State
interface class with virtual default destructor.
class State {
public:
virtual void event() = 0;
virtual ~State() = default; // relevant part
virtual void onCreate() {}
virtual void onDestroy() {}
virtual void onActivate() {}
virtual void onDeactivate() {}
};
And then some classes inheriting from it:
class GameState : public State {
public:
void event() override;
// ...
};
class MenuState : public State {
public:
void event() override;
// ...
};
Compiler generates default move operations if no copy operation or destructor is user-defined. Compiler generates default copy operations if no move operation is user-defined.
Am I correct that by declaring virtual default destructor I have effectively deleted the default move operations?
Will the move operations work for the deriving classes if the base class had implicitly deleted its move operations, and the base class is just an interface without data members?
Is it really sensible to follow the Rule of 5 here? It seems quite a bloat to explicitly delete or default all 5 special member functions.
Upvotes: 3
Views: 638
Reputation: 375
Let's assume your base class has copy (and possibly move) constructors and assignment operators. What would you expect in this case?
MenuState menuState;
State state = menuState; // be aware that this State object is not a MenuState any more
In case your State
class is abstract (if for example onActivate()
was pure virtual) above wouldn't make any sense because a State
instance would not be allowed.
But even if not, any MenuState
members would be sliced, when you put them into a State
object. If instances of your base class don't make much sense on their own, copy and move constructors and assignment operators should rather be deleted.
For derived (concrete) classes copying or moving might make more sense. In this case it can be useful to have protected
copy constructors and assignment operators in the base class. So you cannot instantiate your base class itself, but your derived classes can make use of it.
MenuState menuState;
MenuState copy = menuState; // might be useful
If on the other hand the base class makes sense on its own, public
(and possibly default
) copy and move constructors and assignment operators can be reasonable. This can be the case if derived classes just add some additional information, which is not required whenever you convert your derived objects to base objects.
So it really depends, and that's why it's better to explicitly point out what is intended, public
copy and move, protected
copy and move, or non at all.
Such class hierarchies, however, are often used with pointers (like std::unique_ptr
or std::shared_ptr
). Then a virtual
clone()
method sometimes is more useful.
auto state = std::make_unique<MenuState>();
std::unique_ptr<State> copy = state->clone();
Internally this clone()
method might use the copy constructor, though, which can be public
(be careful of slicing, if your derived classes are not final
) or protected
(if you want to make sure only the clone()
method is used).
Upvotes: 3