I've always heard that you shouldn't inherit from a class without virtual destructors, and I didn't pay much attention because I just don't use inheritance all that often. Does this rule apply even if you don't want to use polymorphism, but you just want all of a class functionality, and you want to add some more? To be concrete, would the following class be safe, with well defined behavior, as long as I didn't use it polymorphically? (i.e. no deleting base pointers to derived objects)
template<typename T>
class SomewhatSafeVector : public std::vector<T>
{
public:
typedef std::vector<T> base;
T& operator[](unsigned n) {
if (n >= base::size())
{
throw IndexOutOfBounds();
}
return base::operator[](n);
}
};
I've always heard that you shouldn't inherit from a class without virtual destructors
This is a rule of thumb given to beginners because explaining all the intricacies take too much time and it is just safer (and not that much costly for exercices programs) to actually give them just a few base lines that work all the times (though may be overkill).
You can perfectly use inheritance without a virtual
destructor in the base class. On the other hand, if the base class has no virtual
method at all, then inheritance is probably the wrong tool for the job. For example: in your case if I use SafeVector<T> sv; sv[3];
then it is safe, however if I do std::vector<T>& v = sv; v[3];
it is not... this is because you are merely hiding the base class method, not overriding it (crank up your warning level, they'll let you know).
The proper way here would be to use composition, and then create forwarding methods to the implementation member for those methods you really use. In practice, it gets tiring because C++ does not support delegation (using attribute.insert;
) so many resort to inheriting...
Another alternative is to provide the safer methods as free methods, since you can always add free methods without restriction. It might feel less idiomatic to people with the "OO" mindset, and some operators cannot be so added.
If you don't intend to use the class polymorphically(no deleting base pointers to derived objects) then it is not Undefined Behavior.
Reference:
C++03 Standard: 5.3.5 Delete
5.3.5/1:
The delete-expression operator destroys a most derived object (1.8) or array created by a new-expression.
delete-expression:
::opt delete cast-expression
::opt delete [ ] cast-expression
5.3.5/3:
In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined. In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.73)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With