1

I implemented a little class hierarchy and need to instantiate subclasses from a factory class. I have the class ConcreteProduct which is derived from AbstractProduct and I have the class ConcreteFactory which is derived from AbstractFactory. My code looks like:

factory.h

#ifndef FACTORY_H
#define FACTORY_H

#include <cstddef>
#include <vector>
#include <memory>

template <typename DATATYPE, typename RETURNTYPE>
class AbstractProduct {
    protected:
        DATATYPE data;
        std::size_t count;
    public:
        explicit AbstractProduct(DATATYPE _data, std::size_t _count):
            data(_data),
            count(_count) {}
        virtual void doSomething() = 0;
};
template <typename DATATYPE, typename RETURNTYPE>
class ConcreteProduct: public AbstractProduct<DATATYPE, RETURNTYPE> {
    public:
        ConcreteProduct(DATATYPE _data, std::size_t _count):
            AbstractProduct<DATATYPE, RETURNTYPE>(_data, _count) {}
        virtual void doSomething() override;
};

template <typename DATATYPE, typename RETURNTYPE>
class AbstractFactory {
    public:
        virtual 
            std::vector<std::unique_ptr<AbstractProduct<DATATYPE, RETURNTYPE>>>
            createProducts(DATATYPE _data) = 0;
};
template <typename DATATYPE, typename RETURNTYPE>
class ConcreteFactory: public AbstractFactory<DATATYPE, RETURNTYPE> {
    public:
        virtual 
            std::vector<std::unique_ptr<ConcreteProduct<DATATYPE, RETURNTYPE>>>
            createProducts(DATATYPE _data) override;
};

#endif

factory.cpp

#include "factory.h"

template class ConcreteProduct<int*, int*>;
template class ConcreteFactory<int*, int*>;

template <typename DATATYPE, typename RETURNTYPE>
void ConcreteProduct<DATATYPE, RETURNTYPE>::doSomething() {
    int a = 5+3;
}

template <typename DATATYPE, typename RETURNTYPE>
std::vector<std::unique_ptr<ConcreteProduct<DATATYPE, RETURNTYPE>>> ConcreteFactory<DATATYPE, RETURNTYPE>::createProducts(DATATYPE _data) {
    std::vector<std::unique_ptr<ConcreteProduct<DATATYPE, RETURNTYPE>>> result;
    for(std::size_t i = 0; i < 5; ++i) {
        result.push_back(std::make_unique<ConcreteProduct<DATATYPE, RETURNTYPE>>(_data, 1));
    }
    return result;
}

main.cpp

#include "factory.h"

int main() {

    int* data = new int[20];

    ConcreteFactory<int*, int*> factory;
    std::vector<std::unique_ptr<ConcreteProduct<int*, int*>>> products = factory.createProducts(data);

    return 0;
}

When I try to compile this with g++ -o factory -std=c++14 main.cpp factory.cpp (g++ 4.9.2), I get this error:

In file included from main.cpp:1:0:
factory.h: In instantiation of ‘class ConcreteFactory<int*, int*>’:
main.cpp:7:33:   required from here
factory.h:39:13: error: invalid covariant return type for ‘std::vector<std::unique_ptr<ConcreteProduct<DATATYPE, RETURNTYPE> > > ConcreteFactory<DATATYPE, RETURNTYPE>::createProducts(DATATYPE) [with DATATYPE = int*; RETURNTYPE = int*]’
             createProducts(DATATYPE _data) override;
             ^
factory.h:32:13: error:   overriding ‘std::vector<std::unique_ptr<AbstractProduct<DATATYPE, RETURNTYPE> > > AbstractFactory<DATATYPE, RETURNTYPE>::createProducts(DATATYPE) [with DATATYPE = int*; RETURNTYPE = int*]’
             createProducts(DATATYPE _data) = 0;
             ^
In file included from factory.cpp:1:0:
factory.h: In instantiation of ‘class ConcreteFactory<int*, int*>’:
factory.cpp:4:16:   required from here
factory.h:39:13: error: invalid covariant return type for ‘std::vector<std::unique_ptr<ConcreteProduct<DATATYPE, RETURNTYPE> > > ConcreteFactory<DATATYPE, RETURNTYPE>::createProducts(DATATYPE) [with DATATYPE = int*; RETURNTYPE = int*]’
             createProducts(DATATYPE _data) override;
             ^
factory.h:32:13: error:   overriding ‘std::vector<std::unique_ptr<AbstractProduct<DATATYPE, RETURNTYPE> > > AbstractFactory<DATATYPE, RETURNTYPE>::createProducts(DATATYPE) [with DATATYPE = int*; RETURNTYPE = int*]’
             createProducts(DATATYPE _data) = 0;
             ^

Since ConcreteProduct is a subclass of AbstractProduct, this should work, shouldn't it? What I am doing wrong?

Community
  • 1
  • 1
Hymir
  • 811
  • 1
  • 10
  • 20
  • This doesn't change anything. When I put the implementation into the header file, the error remains the same :( – Hymir Jan 17 '17 at 11:07
  • `std::vector` has no relation to `std::vector`; likewise `std::vector>` has no relation to `std::vector>`. See [“Invalid covariant return type” errors in nested classes with methods returning template-based objects](http://stackoverflow.com/q/17254381/636019) – ildjarn Jan 17 '17 at 11:16
  • Thanks for the answer. So do i need to implement an implicit cast? Or what would you suggest? – Hymir Jan 17 '17 at 11:18
  • 1
    You need to reconcile the return type or not use virtual functions. It's important to realize that `std::vector>` has no relation to `std::vector>`, but `std::unique_ptr` does know how to play nice with `std::unique_ptr`, so as long as everything uses `std::vector>` you're fine. – ildjarn Jan 17 '17 at 11:22
  • 1
    @Hymir Return a `vector>`. – molbdnilo Jan 17 '17 at 11:22
  • That worked! Thank you very much!!! – Hymir Jan 17 '17 at 11:31
  • @ildjarn You should consider posting your solution as an answer. – François Andrieux Jan 17 '17 at 11:47

0 Answers0