1

I am hoping this is possible in C++.

I have a list of classes that inherit from a common base class (Base). All of these will be compiled as part of the library linked to my program.

I could be adding more classes that derive from Base and will be recompiling everything after I do this.

When my program starts it will gather a vector of all classes (using some preprocessing method I have already implemented) that implement from Base.

What I want to do (you have probably guessed by now) is to create objects from these classes just based on the string names. Is this possible?

Regards

Mark

Mark
  • 1,538
  • 5
  • 24
  • 31
  • In short, propably no - C++ has absolutely no reflection. What exactly do you need to do? Maybe there's a better way. –  Oct 05 '10 at 14:14
  • possible duplicate of [C++: Is there a way to instantiate objects from a string holding their class name? ](http://stackoverflow.com/questions/582331/c-is-there-a-way-to-instantiate-objects-from-a-string-holding-their-class-name) – Steve Townsend Oct 05 '10 at 14:20
  • search for reflection and C++. Usually it involves a map and an associated creation function – Nikko Oct 05 '10 at 14:20
  • 2
    IMHO the easiest way would be to change the code to use a factory function to create the objects and use part of the preprocessing to generate said function. – Timo Geusch Oct 05 '10 at 14:20
  • I wanted to be able to added classes and have the program know and add an instance of an object to a vector of type base. – Mark Oct 05 '10 at 14:25
  • Steve: Nah not quite, the answer there talks about a map, I want to do it dynamically at runtime. – Mark Oct 05 '10 at 14:28
  • Timo: Nice, now thats better, offering a solution. – Mark Oct 05 '10 at 14:29
  • @Mark: you can add and remove items from the map at runtime, you may have to elaborate on your own on the answer, but it really is what you're looking for. – Matthieu M. Oct 05 '10 at 14:31

3 Answers3

2

Well, if you have a preprocessed list of all classes then you can create a construction object that will "know" each of those classes and will construct (by manually searching through the list) them upon request.

Šimon Tóth
  • 35,456
  • 20
  • 106
  • 151
  • This is what I think im looking for. I could make the preprocessor generate code based on the classes it finds, pre compilation. – Mark Oct 05 '10 at 14:33
  • @Mark Well the code is identical to what dgnorton posted, you will just generate it from your preprocessed list. – Šimon Tóth Oct 05 '10 at 14:35
  • Ok now I need a way of running the preprocessing from cmake before compilation. This looks like the way http://www.vtk.org/Wiki/CMake_FAQ#How_do_I_generate_an_executable.2C_then_use_the_executable_to_generate_a_file.3F – Mark Oct 05 '10 at 14:37
2

Depends on what you're trying to do. There are probably better ways to do what you need to do but here's an oversimplified example...

#include <string>

using namespace std;

class b1{};

class d1 : public b1{};

class d2 : public b1{};

...

int main(int argc, char* argv[]) {
   string name(argv[1]);

   b1* b;

   if (name == "d1")
      b = new d1;
   else if (name == "d2")
      b = new d2;
}
dgnorton
  • 2,237
  • 16
  • 12
  • Then I need to add and else everytime I add a new class. Not really what I was looking for. – Mark Oct 05 '10 at 14:31
0

Sure, but not the way you would like. C++ has no reflection, so you have to build the mechanism yourself: (See below for EDIT which implements a map of factory pointers)

#include <string>
#include <vector>
#include <memory>
using namespace std;

class Base
{
};

class Dog : public Base
{
};

class Cat : public Base
{
};

int main()
{
    typedef vector<string> strings;
    strings names;
    names.push_back("Dog");
    names.push_back("Cat");
    names.push_back("Dog");
    names.push_back("Cat");

    typedef vector<Base*> Bases;
    Bases my_objs;

    for( strings::const_iterator it = names.begin(), it_end = names.end(); it != it_end; ++it )
    {
        if( *it == "Dog" )
            my_objs.push_back(new Dog);
        else if( *it == "Cat" )
            my_objs.push_back(new Cat);

    }
}

EDIT:

Any solution you come up with in C++ is going to be fundamentally some variation of the above. One common variation is to try to get rid of the if block by doing some kind of lookup. This can be implemented using a map object which links the name of the object to a function that instantiates it. One thing to note about this approach is that the function pointers in the map have to have the same signature, meaning theDog and Cat factory methods have to take the same number and type of parameters. This is a problem that can be solved using Boost::Any (link) or other heroic methods, but that's beyond the scope of this post.

Here's a solution that implements a map of factory method pointers:

#include <string>
#include <vector>
#include <map>
using namespace std;

class Base
{
public:
    virtual ~Base()  {};
};

class Dog : public Base
{
public:
    static Base* make_dog() { return new Dog; }

};

class Cat : public Base
{
public:
    static Base* make_cat() { return new Cat; }
};

typedef Base*(*ObjFactoryFn)();
typedef map<string, ObjFactoryFn> Factories;


int main()
{
    // set up the map of object factory pointers
    Factories factories;
    factories["Dog"] = &Dog::make_dog;
    factories["Cat"] = &Cat::make_cat;

    // build list of objects we want
    typedef vector<string> strings;
    strings names;
    names.push_back("Dog");
    names.push_back("Cat");
    names.push_back("Dog");
    names.push_back("Cat");

    // build objects using the factory map
    for( strings::const_iterator it = names.begin(), it_end = names.end(); it != it_end; ++it )
    {
        // construct
        Base* my_obj = factories[*it]();    // this should use map's "find" method for robustness
        // destroy
        delete my_obj;
    }

}
John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • You have failed to understand the question. Anything that requires me to add code after creating the class is not what I am looking for. I have found the answer, it involves generating code pre compilation, based on the list of classes. This can be hooked into cmake to make it seamless. – Mark Oct 05 '10 at 14:44
  • Perhaps you've failed to understand the answer? Any "code pre-compilation" is generating something equivalent to what John has recommended. Even if it's a pre-processor macro or a macro executed by cmake, somewhere somehow you are adding something to make the system aware of your new classes. Your question doesn't explain the constraints on where that can occur. This response clearly took some time to write out and answers your question (as posted) perfectly. Stick around, feel welcome, but show a little gratitude to people willing to teach you _exactly_ what you asked to learn about. – Darryl Oct 05 '10 at 15:24
  • @Mark: I'd be interested in seeing the pre-compilation generation of code you've come up with to see how it's different that what I've posted. I'd also be interested in knowing why you feel it necessary to respond with so much attitude to someone who took 20 minutes out of his day to try to help you in good faith. I assume you realize we are unpaid. – John Dibling Oct 05 '10 at 16:20
  • Sorry I apologise for my earlier comment, the solution provided is very helpful and I appreciate the time involved to produce it. Again sorry. – Mark Oct 05 '10 at 17:44