Is inheritance from a base class with no virtual methods bad practice?
I read an answer some time back to a question regarding dynamic_cast. The dynamic_cast failed to work because the base class had no virtual methods. One of the answers said that deriving from classes with no virtual methods generally means a bad design. Is this correct? Even without taking advantage of polymorphis开发者_如何学编程m, I still can't see the wrongness in doing this.
It depends what we're talking about:
- for Traits classes (no data) it's fine (
std::unary_function
comes to mind) - for
private
inheritance (used instead of composition to benefit from Empty Base Optimization) it's fine too
The problem comes when you starts treating such a Derived object polymorphically wrt this Base class. If you ever attain such a position, then it's definite code smell.
Note: Even when noted as fine above, you are still providing the ability to use the class polymorphically, and you thus expose yourself to subtle bugs.
Deriving from a class is always a valid option, for the sake of code reuse.
Sometimes, we are not looking for polymorphic behavior. That's OK - there's a reason we have that option. If this is the case, though, then consider using private inheritance instead - if your class isn't meant to be polymorphic, then there's no reason for anyone to try to use it polymorphically.
Here is an OK example, to factor behaviors into policies (note the protected destructor):
struct some_policy
{
// Some non-virtual interface here
protected:
~some_policy() { ... }
private:
// Some state here
};
struct some_class : some_policy, some_other_policy { ... };
Another Ok example, to avoid code bloat in templates. Note the protected destructor:
struct base_vector
{
// Put everything which doesn't depend
// on a template parameter here
protected:
~base_vector() { ... }
};
template <typename T>
struct vector : base_vector
{ ... };
Another example, called CRTP. Note the protected destructor:
template <typename Base>
struct some_concept
{
void do_something { static_cast<Base*>(this)->do_some_other_thing(); }
protected:
~some_concept() { ... }
};
struct some_class : some_concept<some_class> { ... };
Another example, called Empty Base Optimization. Not really inheritance per se, since it is more a trick to allow the compiler to reserve no space in some_class
for the base class (which acts as a private member).
template <typename T>
struct some_state_which_can_be_empty { ... };
template <typename T>
struct some_class : private some_state_which_can_be_empty<T> { ... };
As a rule of thumb, classes you inherit from should have either virtual or protected destructor.
Inheritance without virtual methods in C++ is nothing more than a code reuse. I can't think of inheritance without polymorphism.
Some classes in the C++ standard library have protected members (which are only meaningful to a derived class) but no virtual member functions. I.e., they're designed for derivation, without having virtuals. This proves that it must generally be bad design to derive from a class without virtuals.
Cheers & hth.,
精彩评论