5

Possible Duplicate:
Is there a way to instantiate objects from a string holding their class name?

In C++, I want to have my user enter the object type name to be created at run-time, and, depending on the string I get from them, the program will instantiate the correct object (in short, I'm implementing factory method pattern). However, if the program has to support a new object type, then modifying existing code is not allowed.

So is it possible to remove all the if...else if...else if... stuff from the method, and still have my program instantiate a correct object of a specific product type (out of many, which are known only at compile time)?

My searching around got me this link: Is there a way to instantiate objects from a string holding their class name? and it seems it's what I want but I can't understand the code at all.

Any help would be really appreciated.

Community
  • 1
  • 1
IcySnow
  • 851
  • 2
  • 14
  • 23
  • @CharlesB you don't need reflection, you can use a factory. – Luchian Grigore Nov 25 '11 at 13:10
  • 1
    @LuchianGrigore: factory is a design pattern, reflection is a language feature. If you want a factory that works without if..else..else... you need a language that has reflection, or a binary plugin architecture, like in Alessandro's answer – CharlesB Nov 25 '11 at 13:13

2 Answers2

5

This will only work if all the required classes are derived from some common base class, and you will generally be limited to using the base interface (though you can work around that with some additional effort). Here's one approach:

// Immutable core code:

#include <map>
#include <string>

class Base
{
  typedef Base * (*crfnptr)(const std::string &);
  typedef std::map<std::string, crfnptr> CreatorMap;

  static CreatorMap creators;

public:
  virtual ~Base() { }
  Base * clone() const { return new Base(*this); }

  static Base * create_from_string(std::string name)
  {
    CreatorMap::const_iterator it = creators.find(name);
    return it == creators.end() ? NULL : it->first();
  }

  static void register(std::string name, crfnptr f)
  {
    creators[name] = f;
  }
};

Now you can add new derived classes from your new code:

// your code:

#include "immutable_core.hpp"

class Foo : public Base
{
public:
  Foo * clone() const { return new Foo(*this); }
  static Foo * create() { return new Foo; }
};

Base::register("Foo", &Foo::create);

To create a class, you simply call Base * p = Base::create_from_string("Foo");.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Are the `clone()` functions needed here? I'm not sure if it's a good idea to strip them out. – Daan Sep 09 '15 at 14:02
  • @Daan: You're right, they're not necessary for the factory per se, but they take the role of the copy constructor in situations where you don't know an object's most-derived type, so they're thematically related. – Kerrek SB Sep 09 '15 at 14:08
  • So if I understand correctly, I need them for seemlessly casting from `Base*` to `Derived*` ? – Daan Sep 09 '15 at 14:38
  • @Daan: No, not at all. You need them to make copies of objects you got from the factory. – Kerrek SB Sep 09 '15 at 15:24
  • Ok, thanks :) I try to avoid having copies so I'll just strip it out. – Daan Sep 09 '15 at 20:04
2

You can do that implementing something like a plugin system. I've implemented this in Linux with dlopen. The program doesn't need to be modified, but you need only add new classes as dynamic libraries that will be loaded at runtime.

You can start here for more info: C++ dlopen mini HOWTO

Alessandro Pezzato
  • 8,603
  • 5
  • 45
  • 63