mercredi 25 mars 2015

Exploiting uniform syntax of value types and references

Let's say we have the following Base class, and two derived classes Derived1 and Derived2:



class Base {
// Some declarations ...
};

class Derived1 : public Base {
// Some declarations ...
public:
vector<int> _array;
};

class Derived2 : public Base {
// Some declarations ...
public:
vector<int> &_array;
};


That is, we have a common class but the underlying data structures are of different types.


Say that we want to access individual elements of the underlying arrays using a uniform interface from a Base pointer. i.e. something like this:



Base *bPtr = new Derived1(...);
int val = bPtr->index(3);


Having a pure virtual function called index in Base is one solution. However, in that case we would need the same int index(uint x) { return _array[x]; } implementation in both of the derived classes. This is ugly, and we cannot implement that function in Base since it does not know about _array.


So we must either (1) change the types of _arrays to the same type (say, to a vector<int>*) and have the implementation of index in Base or (2) have two implementations in Derived1 and Derived in order to make use of a common interface. However I cannot afford (1) since it would add an extra indirection layer to Derived1, and I want to avoid that if possible. Having a number of member variables like that makes (2) horrible since that is a lot of boilerplate and replication, and hard to maintain.


I understand that the two index functions are actually different functions, since they operate on different types. In many other scenarios Derived1 and Derived2 would need separate functions since they have different behaviour (and would be compiled to different object codes). However in the case of C++ the implementations are syntactically similar, so I'm wondering whether there is a way to exploit that.


One possible solution is having a free function:



template <class T>
int index(const T &obj, uint x) {
return obj._array[x];
}


where we declare index a friend of both Derived1 and Derived2. However, this might not be considered elegant since it uses a friend declaration (also declaring friend twice is repetitive).


Hence, my question is: Is there a more elegant way to implement index, while avoiding performance costs and code repetition?


Aucun commentaire:

Enregistrer un commentaire