I inherited from C++ STL container and add my own methods to it. The rationale was such that to the clients, it will look act a regular list, yet has application-specific me
You're correct that you should not inherit from STL containers. Virtual functions would make them meaningfully larger -- the base size of vectors would jump from 12 to 16 bytes (in the implementation I'm using). Besides that, virtual functions are difficult to inline, which can slow down the code. If you find yourself making an array of a million mostly-empty vectors, the difference adds up pretty fast.
You can still get the effect you want by declaring the vector as a member variable in your ItemList and then thunking through any methods that you wish to expose.
class ItemList {
private:
std::vector< Item > mItems;
public:
typedef std::vector< Item >::size_type size_type;
int MaxA();
int SpecialB();
Item &operator[]( size_type offset ) { return mItems[offset]; }
size_type size() const { return mItems.size(); }
};
... and so forth. This is a fair amount of grunt work, but it will give you the effect you asked for.
Since you can only "extend" the vector by using its public interface, it is far more useful to write functions which operate on a vector instead of being part of a vector.
Heck, if you plan it well, make it work with iterators instead of indexes and it'll work with more than just std::vector
(see <algorithm>
for some very good examples).
For example, you could use a functor for the MaxA like this:
struct CmpA {
bool operator()(const Item &item1, const Item &item2) { return item1.a < item2.a; }
}
const int result = std::max_element(v.begin(), v.end(), CmpA()).a;
your specialB could be just as simple with a functor and std::accumulate
EDIT: or for c++11 and later, it can be as simple as:
const int result = std::max_element(v.begin(), v.end(), [](const Item &item1, const Item &item2) {
return item1.a < item2.a;
}).a;
EDIT: you've asked why it is better to do it this way:
if you use algorithms, templates and iterators, it'll work even if you decide to put the items in a std::list<Item>
or whatever. It is simply more versitile and helps code reuseablity.
Plus the functions in <algorithm>
do much of this for you so you can just use little 3 line adapter functors.
EDIT: In addition to this, tgamblin listed some very compelling reasons to not inherit from std::vector
(and most other std containers, including std::string
).