A base class in C++ should have at least a virtual
destructor, if I inherit from the class. Therefore, one should e.g. better not inherit from std::optional
.
The answer here says
If it doesn't have any virtual methods, then you shouldn't be using it as a base. This rules out std::vector and the like.
If I can't safely inherit from std::optional
or std::vector
, I expect them to be final
. That sounds like this keyword was made exactly for this purpose.
Specifies that [...] a class cannot be derived from.
If we ignore the advise, it seems we get undefined behavior when deriving from such classes.
There's even core guideline C.139, "Use final on classes sparingly". And that guideline confirms:
Not every class is meant to be a base class. Most standard-library classes are examples of that (e.g., std::vector and std::string are not designed to be derived from).
IMHO, using final
on such classes would prevent problems.
For which scenario do I need the non-final-ness of std::
-classes?
It is perfectly fine to use these classes like std::vector
as base class.
You just have to know what deriving from a class without virtual destructor means, namely that you can't pass ownership to it via base class reference/pointer.
And you have to be aware what especially public inheritance means if the standard library extends or changes the classes' interface and that it enables implicit conversion to base class pointers/references.
Of course, also, because the functions in the base class are not virtual
you can't pretend that they are and expect e.g. a member function call on a base class reference to call your implementation in the derived class. But that is obvious and applies to every non-virtual
function call in every class. (And non-virtual
should be the default. Making all functions virtual
for no reason would be horrible.) I.e. you can't treat the derived class as an implementation or extension of some abstract interface that the standard library base class implements.
Otherwise there is no UB or anything prohibiting the use of standard library classes as base class or any problem with doing so.
All of this applies exactly the same to any other class without virtual destructor or with other non-virtual
functions and a general rule prohibiting inheritance from classes without virtual destructor is IMO way too strict. Consider for example aggregate classes with base classes or common implementations of std::tuple
and such which rely on inheritance for completely different reasons than polymorphism.
A rule requiring that every base class have only a purely virtual
interface would be even worse. Use OOP principles strictly where it makes sense, but C++ is not fundamentally built on them and most of the standard library for example does not follow OOP principles strictly. Using such a approach is especially detrimental to performance, which is usually the number one reason to use C++ over other high-level languages.
For example I do not see much wrong with e.g. deriving from std::vector
, also publicly, if the goal is just to add some custom member functions for convenience and there is never an attempt made by the user to destroy the class through a pointer/reference to std::vector
. The extra member function wouldn't invalidate use of any of the other member functions, also through a base class pointer/reference, so there is no problem with this.
The worst that could happen is that a future standard version will use the custom member function name for a different functionality.
Even if there was a policy to prohibit deriving from standard library classes, final
was added only with C++11 and because there was no prohibition on deriving in earlier C++ versions, adding final
to standard library classes now would be a breaking change in the language.