3

I'm wondering, is it possible in C++ to use a text value read in from a file to create an object of a class of that name eg.

contents of file: "MyClass"
code: read file
code: instantiate "MyClass" object.

I'd like to avoid a whole series of hardcoded if/then/elses if possible. Sorry I'm not sure how to describe this problem in more technical terms!

5
  • 1
    ... not possible to my knowledge. Any reason you want something like that? Commented Mar 6, 2011 at 3:57
  • Mmmm....ok looks like it might not be a goer. I was wanting to specify a cost function in a config file that would be used by the program when calculating costs. Commented Mar 6, 2011 at 4:05
  • OK, if you want actual code in your file, then ignore my answer. It is, indeed, not a goer. Commented Mar 6, 2011 at 4:26
  • @jollymorphic At the risk of hawking ChaiScript (chaiscript.com) too much, this is exactly the scenario we designed it for. You could put scripted code in an input file and convert that to a boost::function to pass around in your C++ code. Commented Mar 6, 2011 at 5:34
  • This is very common requirement when you are designing an application that can have plugins, particularly if the host window is yours Commented Feb 6, 2019 at 8:39

5 Answers 5

8

As long as you don't mind some restrictions, this is fairly easy to do. The easiest way to do the job restricts you to classes that descend from one common base class. In this case, you can do something like this:

// warning: I've done this before, but none of this code is tested. The idea 
// of the code works, but this probably has at least a few typos and such.
struct functor_base { 
    virtual bool operator()() = 0;
};

You'll then obviously need some concrete classes derived from that base:

struct eval_x : functor_base { 
   virtual bool operator()() { std::cout << "eval_x"; }
};

struct eval_y : functor_base {
    virtual bool operator()() { std::cout << "eval_y"; }
};

Then we need some way to create an object of each type:

functor_base *create_eval_x() { return new eval_x; }
functor_base *create_eval_y() { return new eval_y; }

Finally, we need a map from the names to the factory functions:

// the second template parameter is:
// pointer to function returning `functor_base *` and taking no parameters.
std::map<std::string, functor_base *(*)()> name_mapper;

name_mapper["eval_x"] = create_eval_x;
name_mapper["eval_y"] = create_eval_y;

That (finally!) gives us enough so we can map from a name to a function object:

char *name = "eval_x";

// the map holds pointers to functions, so we need to invoke what it returns 
// to get a pointer to a functor:
functor_base *b = name_mapper.find(name)();

// now we can execute the functor:
(*b)();

// since the object was created dynamically, we need to delete it when we're done:
delete b;

There are, of course, many variations on the general theme. For example, instead of factory functions that create objects dynamically, you can create an instance of each object statically, and just put the address of the static object in the map.

Sign up to request clarification or add additional context in comments.

3 Comments

I... couldn't decide for a while whether to upvote this for cleverness or downvote it for the same reason. :-)
@ceo: Hmmm..I didn't think it was particularly "clever" -- just a simple application of a fairly normal data structure to map from name to functionality. In writing something like an interpreter, it's all pretty common -- and this seems to be just a limited form of interpreter.
how do we do this in python
1

you can use abstract factory to do this. Limitations are the classes need to implement a base class and you need to register the factory class with the abstract factory.

class AbstractFactory;
class Factory;
class Object;

// base marker class for all the classes that need this instantiation strategy
class Object{}

class Factory
{
public:
   //override this in concrete factories
   virtual Object* create() = 0;
};
// helper macro to declare an inner class that's a default factory
#define DECL_DEFAULT_FACTORY(ObjectClass) class Factory : public Factory \
{\
public:\
   Factory(){}\
   virtual ~Factory(){}\
   Object* create(){ return new ObjectClass(); } \
}
// this can be made a singleton
class AbstractFactory
{
public:
   void registerClass(const String& clsName, Factory* factory){ //put this in a std::map }
   void deregisterClass(const String& className){ //remove factory from map and delete the ptr }
   Object* create(const String& className)
   {
     Factory* factory = factories[className];
     if(factory){ return factory->create(); }
     else{ return 0; }
   }
};

so it shall be used like:

class SampleClass : public Object
{ 
//impl goes here 
DECL_DEFAULT_FACTORY(SampleClass);
}

and somewhere else you need to do

abstractFactoryInstance->registerClass("SampleClass",new SampleClass::Factory());

then your AbstractFactory is ready to do

SampleClass* obj = (SampleClass*)(abstractFactoryInstance->create("SampleClass"));

you can further refine the scheme by declaring template classes for Factory

Comments

0

Most C++ frameworks (e.g., MFC, Boost) support some kind of object serialization, though it doesn't generally take the form of a human-readable text file. In C++, all of the class types whose instances are recorded in a file have to be present (i.e., compiled and linked into) a program in order for that program to either write or read (and create objects from) such a file.

Comments

0

With Compiled languages like C++, you won't be able to do so. Such things are only possible with interpreted languages, such as PHP.

Comments

0

What you need is boost serializarion. This will allow you to persist your objects in a file. You can find an example here.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.