Lobster
Lobster

Reputation: 635

C++ array of object constructors

I have several classes named Child1, Child2 ... etc, inherited from object Parent. I need to create an object by its name, for example if I have string "Child1", I need to create object Child1 and so on.

I thought about something like:

struct registry_entry {
    const char* name;
    IREGISTRY* (*initializer)(); 
};

struct registry_entry registry_list[] =
{
    {"xml", &REGISTRY_XML::REGISTRY_XML},
}

But I can't get address of object constructor.I believe that this problem must be already solved, and the solution is pretty simple, but I can't find it.

Upvotes: 2

Views: 101

Answers (2)

Christian Hackl
Christian Hackl

Reputation: 27528

Your code looks very C-like and not very C++-like, but if you can actually use the full power of C++11, I would go with a combination of std::function, lambdas, std::unique_ptr and std::map.

Lambdas can wrap constructors without you having to write separate wrapper functions, std::function allows you to store the lambdas in a map, std::unique_ptr eliminates many memory-management bugs, and std::map performs the actual mapping from strings to initialiser functions.

Here is a complete example:

#include <functional>
#include <string>
#include <memory>
#include <map>
#include <iostream>

struct IREGISTRY {
    virtual ~IREGISTRY() {}
    virtual void print() = 0;
};

struct REGISTRY_XML : IREGISTRY { void print() override { std::cout << "XML\n"; } };
struct REGISTRY_INI : IREGISTRY { void print() override { std::cout << "INI\n"; } };
struct REGISTRY_JSON : IREGISTRY { void print() override { std::cout << "JSON\n"; } };

int main()
{
    std::map<std::string, std::function<std::unique_ptr<IREGISTRY>()>> const registry_list = {
        { "xml", []() { return std::make_unique<REGISTRY_XML>(); } },
        { "ini", []() { return std::make_unique<REGISTRY_INI>(); } },
        { "json", []() { return std::make_unique<REGISTRY_JSON>(); } },
    };

    auto const initializer_iter = registry_list.find("xml");
    if (initializer_iter != registry_list.end())
    {
        auto const initializer = initializer_iter->second;
        auto const registry_ptr = initializer();
        registry_ptr->print();
    }
}

Upvotes: 2

πάντα ῥεῖ
πάντα ῥεῖ

Reputation: 1

Constructors and destructors are special functions and cannot be accessed through function pointers.

You need to create a static member function like

struct REGISTRY_XML {
    static IREGISTRY* create();
};

thus you can refer to it as

struct registry_entry registry_list[] =
{
    {"xml", &REGISTRY_XML::create},
}

Upvotes: 6

Related Questions