The question arises from this answer .
It's not okay to derive from classes that weren't meant to be derived from (standard containers). Composition could be used, although I don't see the advantage right now.
Is it so?
What are the drawbacks of deriving from a standard container such as std::set?
Why is composition preferable?
It is. Asdasdasd's answer makes explicit mention of not deriving from standard containers but it can be extrapolated to any other object container or not, standard or not.
So the rest of the answer will focus (unless otherwise mentioned) on the fact that you should not derive from classes that are not ready to be derived.
Possible failures when destroying objects.
When a class (eg: a container) handles resources (eg memory), it must be responsible for freeing those resources, preferably in its destructor .
The object's destructor is called automatically when the object was created in autospace (stack) and the scope where it was created is left. If the object was created using
new
heap space, it is necessary to call the destructor using the instructiondelete
and that is when things get complicated.We can store a derived class in a pointer to a base class, so the following code is legal but dangerous:
The danger is that the destroyer
std::set
is not virtual. This causes that when destroying aConjunto
by means of a pointer to its base classstd::set<int>
, the destructor of the base class is not invoked and therefore: all the memory requested by the base class is not freed. Of course, nothing happens ifConjuto
it is deleted by means of a pointer to its type or if it is stored in the stack:Since you cannot modify the implementation of objects from foreign libraries 1 , it is impossible for us to correct the problem of the non-virtuality of the del destructor
std::set<int>
and therefore we can cause memory leaks but...What if I don't want to use the class from its base?
Suppose you don't intend to use your class polymorphically, this fixes the problem of no virtual destructor. For this to be possible we should start by changing the type of inheritance to private:
Is this use advisable? It could be in some contexts but I still do not advise it 2 since it can break the principle of minimum surprise ; as a programmer I would expect that a class that derives from
std::set
can be used the same as astd::set
(built the same, traversed the same, managed the same); even if it is an extension of said container I might even consider using it instead ofstd::set
not being able to do so would be " surprising ".What do you advise? two
If a class behaves exactly the same as another except for certain operations, we have different options:
We've already seen pros and cons of drifting, I wouldn't consider it a no-go but it wouldn't be my first choice either; You have to think carefully before using it.
C++ does not have extension classes , but functions can be specialized to deal with certain types and perform certain operations on them:
Unfortunately C++ does not ( yet ) have opaque aliases, so the specialization of
haz_cosas
does not distinguish betweenConjunto
orstd::set<int>
.The composition solves the problem of the absence of opaque aliases and dodges the problems related to inheritance:
I don't think one option is preferable over another, each of the options has pros and cons to take into account and it will depend on the use you want to give to the type to decide on one or the other.
1 It is possible to be able... but should it be?
2 It is a personal opinion, it should not be considered a commandment.