I have an obect called an IndexSet, currently defined as a std::vector, that I want to define as a separate type.
I want to be able to interact with it just as though it were a vector, but I also want type protection so that I don't accidentally use a "normal" vector when I want to use an IndexSet.
I have been able to come up with three options for how to do this, none of which please me. I am hoping that there is a fourth that I am missing.
Option #1: typdef
typdef vector<int> IndexSet
This allows me to use an IndexSet exactly as I would a vector, but it gives me zero type protection. I am able to pass a vector into a function expecting an IndexSet with zero complaints.
Option #2: Public Wrapper Class
class IndexSet
{
public:
vector<int> indexes;
};
This will give me type protection, but it requires me to use a level of indirection interacting with it. Instead of saying set.push_back(1); I have to say set.indexes.push_back(1);
Option #3: Private Wrapper Class
class IndexSet
{
public:
push_back....
operator[]...
etc...
private:
vector<int> indexes
};
This will give me both type protection and allow me to interact directly with the IndexSet as though it were a vector, but ONLY if I first create wrapper methods for every single method of std::vector that I want to use with my IndexSet.
Of course, what I'd really like to do is to just create a new class that inherits from vector but has zero implementation of its own, but I know that the standard library containers do not like to be inherited from.
Are there any other options that I'm missing?
Is there some functionality that differs between an IndexSet
and a vector? Is there some difference in how these objects are used? If the answer is no, then why do you want to do this?
Your typedef does not suffice only if there is something intrinsically wrong with supplying a std::vector<int>
to a functions that expects an IndexSet
. That would suggest that an IndexSet
does not satisfy an is-a relationship with respect to std::vector<int>
. That in turn means that even if you could public inheritance, you shouldn't be doing so.
If the relationship is implemented-by rather than is-a, this suggests using either containment or private (and possibly protected) inheritance. This is much safer than public inheritance from a container class because programmers who use your class have to go out of their way to get a base class pointer. (The way to do it is to use a C-style cast. C-style casts can convert a derived type to a parent class even if the inheritance is not public.)
The advantage of using private inheritance in instead of containment in this case is that you can easily promote selected inherited member functions from private to protected via the using
statement. You would have to write a bunch of wrapper functions if you used containment.
class IndexSet : private std::vector<int> {
public:
// Bunch of constructors, elided.
using std::vector<int>::push_back;
using std::vector<int>::operator[];
using std::vector<int>::cherry_picking_of_only_the_stuff_you_want;
};
Update
There are some non-member functions associated with std::vector
, specifically comparison operators and std::swap
. Making comparable versions for your IndexSet
will require wrapper functions, but there aren't that many (six comparison operators plus std::swap
), and you only need these if that functionality makes sense for this class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With