Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can objects be created based on type_info?

Tags:

c++

Pretty much the title: Can objects be created based on type_info? The purpose of this would be to defer the creation of objects. For instance, here's the original "undeferred" code:

Foo* a = new Foo();
Bar* b = new Bar();

And here's the deferred one:

// Store type indices into a vector
std::vector<std::type_index> types;
types.push_back(std::type_index(typeid(Foo)));
types.push_back(std::type_index(typeid(Bar)));

// Iterate through vector, create objects? Is it possible?

If this is not possible, is there any other way to "defer" the construction of objects?

like image 532
manabreak Avatar asked Nov 04 '14 13:11

manabreak


1 Answers

In c++ there is no equivalent of creating objects based on runtime-known types. Languages such as C# and Java can do this precisely because of their extensive reflection support, which is mostly lacking in c++.

One interesting side effect of all this is that c++ developers are never able to slide into the tempting area of reflecting everything. Because of the sheer convenience of reflection-based development lots of core functionality in enterprise applications built with C# and Java revolves around reflection. I'm thinking in particular of OR/M software and libraries such as AutoMapper for C# which make such extensive use of reflection that the overall performance of applications that use them suffers significantly (speaking from personal experience). It is actually refreshing to me to be prevented from that in c++.

The good news is that plugin architectures are very possible using a double inversion of control architecture. Following is a very simple example showing how a separate dll or so could dynamically register types using basic polymorphism.

#include <string>
#include <list>
#include <unordered_map>
#include <iostream>

// ------------------------------------------------------------
// Host application

class Vehicle
{
public:
    virtual ~Vehicle() {} // Allow proper inheritance
    virtual void Start() = 0; // Start the vehicle
};

class VehicleFactory
{
public:
    virtual ~VehicleFactory() {} // Allow proper inheritance
    virtual Vehicle* Create() = 0;
};

class VehicleTypeFactory
{
public:
    void RegisterFactory(std::string vehicleType, VehicleFactory* vehicleFactory)
    {
        _factories.insert(std::pair<std::string, VehicleFactory*>(vehicleType, vehicleFactory));
    }

    Vehicle* Create(std::string vehicleType)
    {
        return _factories.at(vehicleType)->Create();
    }

    std::list<std::string> GetTypes()
    {
        std::list<std::string> result;
        for(auto& item: _factories)
        {
            result.push_back(item.first);
        }
        return result;
    }

private:
    std::unordered_map<std::string, VehicleFactory*> _factories;
};

class Tractor: public Vehicle
{
public:
    virtual void Start()
    {
        std::cout << "Starting Tractor..." << std::endl;
        std::cout << "Turning on hydraulics..." << std::endl;
    }
};

class TractorFactory: public VehicleFactory
{
public:
    virtual Vehicle* Create()
    {
        return new Tractor();
    }
};


// ------------------------------------------------------------
// Plugin library (.dll, .so)
// plugin introduces brand new type of vehicle
class Limousine: public Vehicle
{
public:
    virtual void Start()
    {
        std::cout << "Starting Limousine..." << std::endl;
        std::cout << "Turning on limo accessories..." << std::endl;
    }
};

class LimousineFactory: public VehicleFactory
{
public:
    virtual Vehicle* Create()
    {
        return new Limousine();
    }
};



// ------------------------------------------------------------
// Host startup: register tractor factory
int main()
{
    VehicleTypeFactory vehicleTypeFactory;
    TractorFactory tractorFactory;
    vehicleTypeFactory.RegisterFactory("tractor", &tractorFactory);

    // ... load plugin(s) which will register other types of factories
    // (
    LimousineFactory limousineFactory;
    vehicleTypeFactory.RegisterFactory("limousine", &limousineFactory);

    // )

    // Now create one of each type of vehicle
    // and tell it to start itself
    for(auto& vehicleType: vehicleTypeFactory.GetTypes())
    {
        auto vehicle = vehicleTypeFactory.Create(vehicleType);
        vehicle->Start();
    }

    return 0;
}

Expected output:

Starting Limousine...
Turning on limo accessories...
Starting Tractor...
Turning on hydraulics...
like image 107
Bob Kocisko Avatar answered Oct 15 '22 15:10

Bob Kocisko