简体   繁体   中英

C++ - Pass a class name as parameter

I have an abstract class. It's a factory.

So other factories can be inherited from this class.

I want to pass that class as an argument to a function.

How do I do that ?

void Gui::registerControlFactory(std::string type, ControlFactory controlFactory)
{
    registeredControls[type] = controlFactory;
} 

here is the abstract class

static class ControlFactory
{
public:
    virtual Control* createControl(json j)=0;
};

and this is the class I want to register through my registerControlFactory function above

static class MyControlsFactory : public ControlFactory
{
    Control* createControl(json j)
    {
        ...
    }
};

I wanna be able to be able to:

gui->registerControlFactory("sometype", MyControlsFactory );

I get an error :

Type name is not allowed

How can I do this in C++?

Thanks for your help

To get the behavior you're probably looking for, you'll want to swap things to pointers:

// the interface will look like:
void Gui::registerControlFactory(std::string type, std::unqiue_ptr<ControlFactory> controlFactory)

// and then when registering:
gui->registerControlFactory("sometype", std::make_unique<MyControlsFactory>());

If you want to avoid creating the class altogether (which is sounds like is your goal), you could switch to std::function< Control()> instead of ControlFactory s:

using Factory = std::function<Control()>;
void Gui::registerControlFactory(std::string type, Factory controlFactory) {
    // assuming this is a std::map<std::string, Factory>
    registeredControls[type] = std::move(controlFactory);
}

// then you could use it like:
gui->registerControlFactory("sometype", [](){ return build_control_thing(); });

Also I don't think C++ has a notion of a static class so that keyword can probably be omitted (assuming it compiles in the first place).

You generally pass objects, or references and pointers to objects, around; C++ can handle type names as parameters only in templates.

The declaration void Gui::registerControlFactory(std::string type, ControlFactory controlFactory) seems odd, given that ControlFactory is an abstract type that cannot be instantiated. (If you come C# or Java make sure to understand that in C++ objects are passed around, not references, unless a parameter is explicitly declared a reference.)

What I would expect here as a general pattern is a reference or a pointer to the base class which enables you to pass a reference or pointer to a derived class implementing this interface. That implementation would have a constructor and no pure virtual functions any longer, so one could readily create objects of that derived factory type.

If the declaration were void Gui::registerControlFactory(std::string type, ControlFactory *controlFactory) you would simply say something like

gui->registerControlFactory("sometype", new MyControlsFactory);

This assumes that the GUI takes ownership of the factory and disposes it when done, or that the GUI's lifetime is that of the program anyway so that no deallocation is necessary. If that is not the case you need to memorize the address of the new control factory somewhere before passing it to the gui.

It looks like you want to store the types in a map and instantiate an object based on the key and what type is stored in the map. C++ can't do this how you think, so you'll have to work around it.

One option would be to store lambdas in the map. Something like:

using ControlBuilder = std::function<Control*(const json&)>;
using FactoryMap = std::map<std::string, ControlBuilder>;

FactoryMap registeredControls;

void Gui::registerControlFactory(std::string type, ControlBuilder buildFunc)
{
    registeredControls[type] = buildFunc;
}

So now you can do something like:

gui->registerControlFactory("sometype", [](const json& j)
    { 
         MyControlsFactory factory; 
         return factory.createControl(j);
    });

This won't instantiate the MyControlsFactory object until you're ready to call it, which you can do like so:

auto control = registeredControls["sometype"](somejsonobject);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM