mardi 3 mars 2015

Polymorphism in C++ STL containers

I was wondering if an elegant solution exists to this problem.


Suppose the following:



class Base {
private:
int data;
protected:
Base(int data) : data(data) { }
int getData() const { return data; }
virtual bool someOp() = 0;
}

class Derived1 : public Base {
private:
int data2;
public:
Derived1(int data, int data2) : Base(data), data2(data2) { }
int getData2() const { return data2; }
bool someOp() override { /* something */ }
}

class Derived2 : public Base {
private:
float data2;
public:
Derived1(int data, float data2) : Base(data), data2(data2) { }
float getData2() const { return data2; }
bool someOp() override { /* something */ }
}


And suppose that I have the total control over the hierarchy so I can assume that Base won't get extended, nor any DerivedX class.


Now I want to store them in a std::vector, if I want to use polymorphism I'm forced to store pointers otherwise object slicing will prevent me to store the additional derived properties. So I'm basically forced to use a std::vector<unique_ptr<Base>>.


But let's assume that I need to store plenty of these objects and I don't want to waste for double heap allocation (the internal std::vector + the object itself) and that at the same time I can assume that:



  • the class hierarchy is perfectly defined and won't be extended without knowing it

  • sizeof(DerivedX) won't be so larger than sizeof(Base)


So I'm wondering if there is an elegant way to keep polymorphism and avoid storing pointers. I could think of some solutions like



class Base {
enum {
DERIVED1,
DERIVED2
} type;

int data;
union {
int derived1data;
float derived2data;
}

bool someOp() {
if (this->type == DERIVED1) ...
else if ..
}
}


But this is clearly not elegant. I could also try to exploit the fact that object slicing shouldn't occur if sizeof(Derived) == sizeof(Base) by using a protected union in Base and accessing it from Derived and casting the address to elements in the std::vector to the desired type (according to an enum) but this sounds ugly too.


Aucun commentaire:

Enregistrer un commentaire