Search code examples
c++templatescovariant

C++ containers, covariance and template


I have some issues to find a relevant solution to my problem. I have to return some data from a class, and the type of data kind of depends on the class. My first solution was this :

class Base
{
    virtual QVector<Data*> getData() const = 0;
};

class Derived : public Base
{
   virtual QVector<DerviedData*> getData() const = 0;
};

But I know this is impossible, even if DerivedData extends Data, because of invalid covariant return types.

So I came up with another idea which implies template. What I did is I turned the Base class into a template class :

template<class T>
class Base
{
    virtual QVector<T*> getData() const = 0;
}

And then I could write a Derivedconstructor like that :

Derived::Derived() : Base<DerivedData>() {}

But know I have another problem. Suppose that I write another class, which has a method taking any Base class in parameters.

void Foo::doSomething(Base* b) { 
    b->getData(); 
}

This does not compile and says

invalid use of template-name 'Base' without an argument list

which I understand perfectly.

Supposing that my code will look like that :

DerivedClass1 d1;
DerivedClass2 d2;
DerivedClass3 d3;

this->doSomething(&d1);
this->doSomething(&d2);
this->doSomething(&d3);

What are my solutions here ? May I do something like "templating" the method doSomething ?

this->doSomething<DerivedData>(&d1);

With a protoype like

template<class T>
void doSomething(Base<T>* b);

Is that possible ? Is that a good way of thinking ? Coming from Java, I used to resolve such problems by using wildcards

abstract List<? extends Data> getData();

But I heard there is stricly speaking no such things in C++ (more or less simulable with such things as std::is_base_of).

Thank you for your time.


Solution

  • You can let Derived::getData() return QVector<Data*>. When you need to use it, find out if the pointers in QVector is to Data or DerivedData, using dynamic_cast or similar method.