Home > Software engineering >  How to write wrappers for classes in c that overrides some member and inherits other members
How to write wrappers for classes in c that overrides some member and inherits other members

Time:04-01

I want to implement a custom vector class myVector<dataT> which is identical to std::vector expect that its index starts from an offset which is given as parameter.

Example usage below:

myVector<int> vec(3,0,1); // length=3, initial_value=0, offset=1
assert(vec.size()==3);
vec[1]=1, vec[2]=2, vec[3]=3;
assert(vec[1]==1);
assert(vec[3]==3);

Basically I want to override the dataT& operator[] method while all other methods remain the same. But I want handle cases where offset is a variable instead of a constant.

If offset is constant, I can declare it as template parameter. But this way I cannot pass a variable as offset.

template <typename dataT, size_t offset>
class myVector{
  //definition
};

myVector<int, 1> vec; //valid
int offset=1;
myVector<int, offset> vec; //invalid

I have several possible way to implement myVector in mind, each requires some boiler-plate code:

Method 1: Inherit std::vector, accept offset as parameter of constructor

template <typename dataT>
class myVector : public std::vector {
  myVector(int n, int v0, int offset) {}
  dataT& operator [] (int index) {return this->at(index-offset);}
}

By inheriting, methods like size, push_back works automatically. But to accept offset as parameter of constructor, I have to make changes to all overloaded constructors, which can be verbose.

Method 2: Inherit std::vector, make offset a data member.

Similar to method 1, but we don't pass offset as constructor parameter. Instead, we use setOffset() to assign value to it.

While this method gets rid of most boilerplate code, every myVector definition requires a setOffset, which is also not elegant.

Method 3: std::vector as data member of myVector.

template <typename dataT>
class myVector {
  std::vector<dataT> stdVector;
  myVector(const std::vector<dataT> _stdVector, int offset) {}
}

This way definition/initialization of myVector becomes simple, but we need to write myVector::size(), myVector::push_back(), which is also verbose.

So, I have concerns about all 3 methods mentioned above. Is there any elegant implementation that both makes initialization simple and do not involve boilerplate code? Thanks!

CodePudding user response:

Method 4: make offset the first parameter to the constructor, use variadic parameters for the rest, and perfect-forward them.

template<typename ...Args>
myVector(int offset, Args && ...args) : std::vector{std::forward<Args>(args)...}
{
}

This solves the immediate problem of a single implementation for overriding all of std::vector's constructors.

Now, there are other issues with subclassing std::vector, and all other C library containers which have been talked about ad-infinitum before. That may or may not be of a concern to you, you should carefully consider the implications of that (the usual objects are a lack of a virtual destructor). But, that wasn't in the scope of the original question...

  •  Tags:  
  • c
  • Related