Some func / class to create class instances by a char * or string in C ++

1

It is possible to create a instance of a class by searching for char * or string in c ++ 11 strong>: ex:

class MyClass:basic_class{};
basic_class* m = (basic_class*)new(typer("MyClass"));

I do not know if it's "typer" something like this? there is not? ... thanks.

    
asked by calimpio 25.05.2017 в 13:33
source

2 answers

0

Yes, regardless of the reputation that may have to create an object according to the name of its type, one way to do it can be using the "Factory" design pattern, with what could be put, for example:

std::unique_ptr<BasicClass> m = CreateMyClass("Flora");

And it could be implemented as:

#include <cstdio>
#include <memory>
#include <vector>

struct BasicClass {
    virtual void hola() = 0;
    virtual ~BasicClass() { }
};

struct Flora : public BasicClass {
    void hola() override {
        puts("Hola Flora.");
    }
};

struct Fauna : public BasicClass {
    void hola() override {
        puts("Hola Fauna.");
    }
};

std::unique_ptr<BasicClass> CreateMyClass(const char* name)
{
    if (!memcmp(name, "Flora", 5))
        return std::make_unique<Flora>();
    else if (!memcmp(name, "Fauna", 5))
        return std::make_unique<Fauna>();
    else
        throw std::runtime_error("ni Flora ni Fauna");
}


int main()
{
   std::unique_ptr<BasicClass> m = CreateMyClass("Flora");
}
    
answered by 29.05.2017 в 14:12
0

In programming, the design patterns are constantly used. The design patterns are templates oriented to the resolution of recurring problems in programming:

  • dependency reduction
  • coupling reduction
  • interface simplification
  • resource management
  • ...

One of these patterns is, as commented by @asdasdasd, the Factoria pattern. This pattern raises the possibility of having a unified interface that allows creating objects of different nature.

The design of the factory is somewhat free, although in C ++ the designs are implemented using classes. An example:

class Base;

template<class T>
Base* CreadorDeObjetos()
{ return new T; }

class Factoria
{
  static std::unordered_map<std::string,std::function<Base*()>> m_creadores;

public:
  static Base* NuevoObjeto(std::string const& nombre)
  {
    Base* toReturn = nullptr;

    auto it = m_creadores.find(nombre);
    if( it != m_creadores.end() )
      toReturn = it->second();

    return toReturn;
  }

  template<class T>
  static void RegistrarObjeto(std::string const& nombre)
  {
    m_creadores.insert(std::make_pair(nombre,&CreadorDeObjetos<T>));
  }
};

std::unordered_map<std::string,std::function<Base*()>> Factoria::m_creadores = {};

struct Base
{
  virtual void Test() = 0;

  virtual ~Base()
  { }
};

struct Derivada1 : Base
{
  void Test() override
  { std::cout << "-- Derivada1 ok\n"; }
};

struct Derivada2 : Base
{
  void Test() override
  { std::cout << "-- Derivada2 ok\n"; }
};

int main()
{
  Factoria::RegistrarObjeto<Derivada1>("Derivada1");
  Factoria::RegistrarObjeto<Derivada2>("Derivada1");

  Base* a = Factoria::NuevoObjeto("Derivada1");
  if( a )
    a->Test();
  else
    std::cout << "Derivada1 no esta registrado\n";

  Base* b = Factoria::NuevoObjeto("Derivada2");
  if( b )
    b->Test();
  else
    std::cout << "Derivada2 no esta registrado\n";

  Base* c = Factoria::NuevoObjeto("d3");
  if( c )
    c->Test();
  else
    std::cout << "d3 no esta registrado\n";
}

Making use of macros the system can be left a little cleaner:

// Factoria de objetos
class Base;

class Factoria
{
protected:
  static std::unordered_map<std::string,std::function<Base*()>> m_creadores;

public:
  static Base* NuevoObjeto(std::string const& nombre)
  {
    Base* toReturn = nullptr;

    auto it = m_creadores.find(nombre);
    if( it != m_creadores.end() )
      toReturn = it->second();

    return toReturn;
  }
};

std::unordered_map<std::string,std::function<Base*()>> Factoria::m_creadores = {};

// Utilidad para registrar los objetos
template<class T>
class RegistradorObjetos : Factoria
{
  static Base* CreadorDeObjetos()
  { return new T; }

public:
  RegistradorObjetos(std::string const& nombre)
  {
    m_creadores.insert(std::make_pair(nombre,&CreadorDeObjetos));
  }
};

// Macro (opcional) para registrar los objetos
#define RegistrarNuevoObjeto(obj) \
  static RegistradorObjetos<obj> obj##_dummy(#obj)

// Clase base
struct Base
{
  virtual void Test() = 0;

  virtual ~Base()
  { }
};

// Clases a introducir en la factoria
struct Derivada1 : Base
{
  void Test() override
  { std::cout << "-- Derivada1 ok\n"; }
};

struct Derivada2 : Base
{
  void Test() override
  { std::cout << "-- Derivada1 ok\n"; }
};

// Se registran las clases
// Ya no hace falta poner el nombre convertido en cadena
// y si nos equivocamos en el nombre salta un error en tiempo de compilacion
RegistrarNuevoObjeto(Derivada1);
RegistrarNuevoObjeto(Derivada2);

int main()
{
  // Mismo codigo que en el primer ejemplo
}
    
answered by 29.05.2017 в 15:24