简体   繁体   中英

Composition or inheritance when extending std::vector?

I want to create a html query object that has all the properties of a vector (can be iterated through, has all the access functions) BUT it should parse the input first before storing it, so a string like "/my/websites/path" should be split into 3 different elements inside the container and there should be no way around that (so the query string is always valid and can't be tempered with).

Now I reflected a bit on whether to do this by inheritance or by composition.

struct query
{
    std::vector<std::string_view> str_;
};

struct query2 : std::vector<std::string_view>
{
};

Here are my thoughts:

Inheritance:

Con :

  • I have to make sure all critical accessor signatures such as vector::emplace or vector::insert as well as ctors are implemented (or deleted) or else the user can bypass the above mentioned "contract". This becomes quite tedious for a class type that has 10 constructors alone, not to speak of all the input function signatures.

Pro:

  • All else facilities are provided (eg iterator interface)
  • I semantically "extend" the vector interface, eg Java uses inheritance in this case.

Composition

Con :

  • I need to write all the accessors myself (reduced set but still).
  • Iterator facility not included, need to write that myself as well.
  • Won't be accepted by functions that accept vector base class (minor problem).

Pro :

  • Better control over the class, further extensions of the vector class (eg an additional accessor signature) won't allow for bypasses.
  • Possibly easier to understand for other users (and myself).

What is best to use in my situation? Maybe there's a solution that tops both and didn't come to my mind.

The key part is that you don't want to expose the non-const vector methods, so inheritance isn't an option (because: 1. one can cast to the base class reference, and modify the elements freely; and even if you ignore that, 2. hiding the unwanted methods one by one is tedious).

This leaves composition. I would make the vector a private member, with a getter that returns a const reference. Then you don't have to reimplement its interface.

If you do decide to reimplement the interface, at least you don't need to reimplement iterators, because you can reuse vector's const iterators.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM