Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inheriting from classes without virtual destructors

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);
    }
};
like image 569
Benjamin Lindley Avatar asked Mar 28 '12 14:03

Benjamin Lindley


2 Answers

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.

like image 155
Matthieu M. Avatar answered Sep 25 '22 23:09

Matthieu M.


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)

like image 23
Alok Save Avatar answered Sep 21 '22 23:09

Alok Save