Reputation: 4523
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?
Upvotes: 5
Views: 655
Reputation: 33116
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.
Upvotes: 3
Reputation:
Let's face it, one solution has all the advantages and just one disadvantage.
If you subclass std::vector, you just have to make sure you don't mix pointers to std::vector and your class, so nobody will delete a pointer to std::vector when it is actually of your subclass.
Whether this is feasible depends on your project. If this is an object that will be used by alot of people, in a public library, an OSS project etc, you might be safer wrapping it, else just subclass std::vector
. You'll be fine.
Don't forget to add a comment at your class interface explaining the dangers. And you might be able do disable casting operators for extra safety (make your ctor explicit, ...).
Upvotes: 1
Reputation: 96241
This sounds like a job for....BOOST_STRONG_TYPEDEF
. http://www.boost.org/doc/libs/1_54_0/boost/serialization/strong_typedef.hpp
BOOST_STRONG_TYPEDEF(std::vector<int>, IndexSet)
Upvotes: 0