c++classclass-factory

Can I create class factory for a constructor with parameter?


I am using a class factory to create objects dynamically. I used this answer for its simplicity (and because I am using Qt).

But now I realize I must add an argument to my constructor

Item(bool newItem /* = true*/);

instead of

Item();

for the code in the referred answer:

template <typename T>
class ClassFactory
{
public:
    template <typename TDerived>
    void registerType(QString shape)
    {
        _createFuncs[shape] = &createFunc<TDerived>;
    }    
    T* create(QString shape)
    {
        typename QMap<QString, PCreateFunc>::const_iterator it = _createFuncs.find(shape);
        if (it != _createFuncs.end())
        {
            return it.value()();
        }
        return NULL;
    }    
private:
    template <typename TDerived>
    static T* createFunc()
    {
        return new TDerived();
    }
    typedef T* (*PCreateFunc)();
    QMap<QString, PCreateFunc> _createFuncs;
};

I registered the class

classFactory.registerType <Type1_Item> ("type1");

when needed, I called

Item* item = classFactory.create("type1");

I am trying to add an additional argument in the class factory, to represent the constructor argument, but my attempts all result in error.

Why do I need it : simple case:

To be able to call the "load" function, an object must exist - which means that if I create a new object, I will trigger an open file dialog even though I do not need it.

The work around that I see is, to have a constructor followed by a setup function. But... that means constructing an object always requires a 2-function call, which seems like bad design.

that is why I am looking for a way to register and call the classes using simple calls like

classFactory.registerType <Type1_Item> ("type1", bool);
Item* item = classFactory.create("type1", true);

Is it possible, and how can I do it ?


Solution

  • You may use this modified version

    template <typename T, typename ... Ts>
    class ClassFactory
    {
    public:
        template <typename TDerived>
        void registerType(QString shape)
        {
            _createFuncs[shape] = &createFunc<TDerived>;
        }    
        T* create(QString shape, Ts... args)
        {
            typename QMap<QString, PCreateFunc>::const_iterator it = _createFuncs.find(shape);
            if (it != _createFuncs.end())
            {
                return it.value()(args...);
            }
            return nullptr;
        }    
    private:
        template <typename TDerived>
        static T* createFunc(Ts... args)
        {
            return new TDerived(args);
        }
        typedef T* (*PCreateFunc)(Ts...);
        QMap<QString, PCreateFunc> _createFuncs;
    };
    

    And use it

    ClassFactory<Item, bool> classFactory;
    classFactory.registerType <Type1_Item> ("type1");
    
    Item* item = classFactory.create("type1", true);