Search code examples
c++inheritancefactory-pattern

C++ Programm calls superclass method instead of subclass method in factory pattern


I'd like to build a factory for my Source-Plugins like that:

class PluginFactory {
public:
    PluginFactory(){};
    virtual ~PluginFactory(){};

    static MySource* getSourceById(int id, ParameterList& pList){
        switch (id){
            case 1:
                return new StringSource(pList);
            default:
                std::cout << "Unknown PluginId!" << std::endl;
                return nullptr;
        }

    }
};

MySource cannot be abstract like usual in the pattern because it will later be used in a template class.

When I call a method of the returned MySource* I get the method of the superclass MySource instead of the overridden method of the subclass StringSource.

Any ideas how to fix this?

EDIT:

I declared the superclass method as vritual:

MySource{
    ...
    virtual std::streamsize read(char* s, std::streamsize n){
    ...
    }
};

I added the override command to the subclasses' read-Method:

class StringSource: public MySource {
    ...
std::streamsize read(char* s, std::streamsize n) override
{
    ...
}

};

But it still uses the superclass method. There has to be another reason...

Btw. I put the Source-Class into a boost::iostream::filtering_istream like this:

MySource* source = PluginFactory::getSourceById(1, pluginList[0].second);
boost::iostreams::filtering_istream in;
in.push(*source);

So I don't call the read-method myself.


Solution

  • The problem is this:

    in.push(*source);
    

    According to the documentation, this will copy the argument. Since your base class is copyable and not abstract, you encounter the slicing problem where only the base sub-object is copied.

    You should be able to fix it by passing a reference wrapper instead:

    in.push(std::ref(*source));
    

    I would suggest that you make the base class abstract (or at the very least uncopyable), to prevent the possiblity of slicing. I don't understand your reason for not making it abstract; but whatever requires it to be concrete sounds scary and error-prone.

    UPDATE: Since you made it concrete just so you could pass it to this function, you should make it abstract again, and pass a reference wrapper instead.