Max Frai
Max Frai

Reputation: 64366

Make object by its name

is it possible to return exemplar of object using passed type name (string) in c++? I have some base abstract class Base and a few derivates. Example code:

class Base
{
   /* ... */
};

class Der1 : public Base
{
   /* ... */
};

class Der2 : public Base
{
   /* ... */
};

And I need function like:

Base *objectByType(const std::string &name);

Number of derivates classes are changeable and I don't want to make something like switching of name and returning by hands new object type. Is it possible in c++ to do that automatically anyway?

p.s. usage should looks like:

dynamic_cast<Der1>(objectByType("Der1"));

I need pure c++ code (crossplatform). Using boost is permissible.

Upvotes: 2

Views: 611

Answers (5)

davka
davka

Reputation: 14692

There is a nice trick which allows you to write a factory method without a sequence of if...else if....

(note that, AFAIK, it is indeed not possible to do what you want in C++ as this code is generated in the compile time. A "Factory Method" Design Pattern exists for this purpose)

First, you define a global repository for your derived classes. It can be in the form std::map<std::string, Base*>, i.e. maps a name of the derived class to an instance of that class.

For each derived class you define a default constructor which adds an object of that class to the repository under class's name. You also define a static instance of the class:

// file: der1.h
#include "repository.h"

class Der1: public Base {
public:
  Der1() { repository[std::string("Der1")] = this; }
};

// file: der1.cpp
static Der1 der1Initializer;

Constructors of static variables are run even before main(), so when your main starts you already have the repository initialized with instances of all derived classes.

Your factory method (e.g. Base::getObject(const std::string&)) needs to search the repository map for the class name. It then uses the clone() method of the object it finds to get a new object of the same type. You of course need to implement clone for each subclass.

The advantage of this approach is that when you are adding a new derived class your additions are restricted only to the file(s) implementing the new class. The repository and the factory code will not change. You will still need to recompile your program, of course.

Upvotes: 2

peoro
peoro

Reputation: 26060

C++ doesn't support reflection.

In my opinion this is the single point where Java beats C++.
(ope not to get too many down votes for this...)

You could achieve something like that by using a custom preprocessor, similar to how MOC does for Qt.

Upvotes: 0

Philipp
Philipp

Reputation: 49850

It is not possible. You have to write the objectByType function yourself:

Base* objectByType(const std::string& name) {
  if (name == "Der1")
    return new Der1;
  else if (name == "Der2")
    return new Der2;
  // other possible tests
  throw std::invalid_argument("Unknown type name " + name);
}

Upvotes: 0

Sean
Sean

Reputation: 62532

It's not possible to do this in C++.

One options is to write a factory and switch on the name passed in, but I see you don't want to do that. C++ doesn't provide any real runtime reflection support beyond dynamic_cast, so this type of problem is tough to solve.

Upvotes: 2

Marnix
Marnix

Reputation: 6547

Yes that is possible! Check this very funny class called Activator You can create everything by Type and string and can even give a List of parameters, so the method will call the appropriate constructor with the best set of arguments.

Upvotes: 0

Related Questions