Subclass/Inherit Standard Containers

Subclass/inherit standard containers?

Maybe many people here will not like this answer, but it is time for some heresy to be told and yes ... be told also that "the king is naked!"

All the motivation against the derivation are weak. Derivation is not different than composition. It's just a way to "put things together".
Composition puts things together giving them names, inheritance does it without giving explicit names.

If you need a vector that has the same interface and implementation of std::vector plus something more, you can:

  • use composition and rewrite all the embedded object function prototypes implementing function that delegates them (and if they are 10000... yes: be prepared to rewrite all those 10000) or...

  • inherit it and add just what you need (and ... just rewrite constructors, until C++ lawyers will decide to let them be inheritable as well: I still remember 10 year ago zealot discussion about "why ctors cannot call each other" and why it is a "bad bad bad thing" ... until C++11 permitted it and suddenly all those zealots shut up!) and let the new destructor be non-virtual as it was in the original one.

Just like for every class that has some virtual method and some not, you know you cannot pretend to invoke the non-virtual method of derived by addressing the base, the same applies for delete. There is no reason just for delete to pretend any particular special care.

A programmer who knows that whatever is not virtual isn't callable addressing the base, also knows not to use delete on your base after allocating your derived.

All the "avoid this", "don't do that", always sound as "moralization" of something that is natively agnostic. All the features of a language exist to solve some problem. The fact a given way to solve the problem is good or bad depends on the context, not on the feature itself.

If what you're doing needs to serve many containers, inheritance is probably not the way (you have to redo for all). If it is for a specific case ... inheritance is a way to compose. Forget OOP purisms: C++ is not a "pure OOP" language, and containers are not OOP at all.

Are STL containers designed to allow inheritance? [duplicate]

Are STL containers designed to allow inheritance or not?

Standard library containers allow Inheritance. Nothing stops you from inheriting from a standard library container class. You will not get any compilation errors if you do so.

But what they are not designed for is to allow is destruction of your derived class object through Base class pointer. So if you want to use inheritance for such a scenario(in short for dynamic polymorphism) then standard library containers are clearly not designed for it.

Is virtual destructor required for inheritance?

Base class destructor is only required to be virtual if you intend to call delete on base class pointer pointed to a derived class object. It will result in Undefined behavior if base class destructor is not virtual.

So to summarize, the rule is:

If you need inheritance for dynamic polymorphism standard library container classes are not designed for it, but If you don't need that you can safely inherit from them.

Note: Your analysis in the answer link you provided is correct. It just didn't get responses probably because the answer was posted long(a few years) after the original Q was posted. You have my +1 there now.

Thou shalt not inherit from std::vector

Actually, there is nothing wrong with public inheritance of std::vector. If you need this, just do that.

I would suggest doing that only if it is really necessary. Only if you can't do what you want with free functions (e.g. should keep some state).

The problem is that MyVector is a new entity. It means a new C++ developer should know what the hell it is before using it. What's the difference between std::vector and MyVector? Which one is better to use here and there? What if I need to move std::vector to MyVector? May I just use swap() or not?

Do not produce new entities just to make something to look better. These entities (especially, such common) aren't going to live in vacuum. They will live in mixed environment with constantly increased entropy.

Is it okay to inherit implementation from STL containers, rather than delegate?

The risk is deallocating through a pointer to the base class (delete, delete[], and potentially other deallocation methods). Since these classes (deque, map, string, etc.) don't have virtual dtors, it's impossible to clean them up properly with only a pointer to those classes:

struct BadExample : vector<int> {};
int main() {
vector<int>* p = new BadExample();
delete p; // this is Undefined Behavior
return 0;
}

That said, if you're willing to make sure you never accidentally do this, there's little major drawback to inheriting them—but in some cases that's a big if. Other drawbacks include clashing with implementation specifics and extensions (some of which may not use reserved identifiers) and dealing with bloated interfaces (string in particular). However, inheritance is intended in some cases, as container adapters like stack have a protected member c (the underlying container they adapt), and it's almost only accessible from a derived class instance.

Instead of either inheritance or composition, consider writing free functions which take either an iterator pair or a container reference, and operate on that. Practically all of <algorithm> is an example of this; and make_heap, pop_heap, and push_heap, in particular, are an example of using free functions instead of a domain-specific container.

So, use the container classes for your data types, and still call the free functions for your domain-specific logic. But you can still achieve some modularity using a typedef, which allows you to both simplify declaring them and provides a single point if part of them needs to change:

typedef std::deque<int, MyAllocator> Example;
// ...
Example c (42);
example_algorithm(c);
example_algorithm2(c.begin() + 5, c.end() - 5);
Example::iterator i; // nested types are especially easier

Notice the value_type and allocator can change without affecting later code using the typedef, and even the container can change from a deque to a vector.

Inheriting from std::vector

I think this answer perfectly answers your question.

It's not impossible to inherit from std::vector, it just probably would be very limited (due to no virtual destructor), quite confusing to others and extending by composition would be better/easier/more maintainable than inheritance anyway.

Perhaps Stroustrup simply wanted to show it's doable, but not necessarily to imply that he suggests it.



Related Topics



Leave a reply



Submit