Question

Is there any way to add a field to a class at runtime ( a field that didn't exist before ) ? Something like this snippet :

Myobject *ob; // create an object
ob->addField("newField",44); // we add the field to the class and we assign an initial value to it
printf("%d",ob->newField); // now we can access that field

I don't really care how it would be done , I don't care if it's an ugly hack or not , I would like to know if it could be done , and a small example , if possible .

Another Example: say I have an XML file describing this class :

<class name="MyClass">
   <member name="field1" />
   <member name="field2" />
</class>

and I want to "add" the fields "field1" and "field2" to the class (assuming the class already exists) . Let's say this is the code for the class :

class MyClass {
};

I don't want to create a class at runtime , I just want to add members/fields to an existing one .

Thank you !

Was it helpful?

Solution

Use a map and a variant.

For example, using boost::variant. See http://www.boost.org/doc/libs/1_36_0/doc/html/variant.html

(But of course, you can create your own, to suit the types of your XML attributes.)

#include <map>
#include <boost/variant.hpp>

typedef boost::variant< int, std::string > MyValue ;
typedef std::map<std::string, MyValue> MyValueMap ;

By adding MyValueMap as a member of your class, you can add properties according to their names. Which means the code:

oMyValueMap.insert(std::make_pair("newField", 44)) ;
oMyValueMap.insert(std::make_pair("newField2", "Hello World")) ;
std::cout << oMyValueMap["newField"] ;
std::cout << oMyValueMap["newField2"] ;

By encapsulating it in a MyObject class, and adding the right overloaded accessors in this MyObject class, the code above becomes somewhat clearer:

oMyObject.addField("newField", 44) ;
oMyObject.addField("newField2", "Hello World") ;
std::cout << oMyObject["newField"] ;
std::cout << oMyObject["newField2"] ;

But you lose somewhat the type safety of C++ doing so. But for XML, this is unavoidable, I guess.

OTHER TIPS

There's no way to do it in the way you've described, since the compiler needs to resolve the reference at compile time - it will generate an error.

But see The Universal Design Pattern.

You can't make that syntax work (because of static checking at compile time), but if you're willing to modify the syntax, you can achieve the same effect pretty easily. It would be fairly easy to have a dictionary member with a string->blob mapping, and have member functions like:

template< typename T > T get_member( string name );
template< typename T > void set_member( string name, T value );

You could make the syntax more compact/tricky if you want (eg: using a '->' operator override). There are also some compiler-specific tricks you could possibly leverage (MSVC supports __declspec(property), for example, which allows you to map references to a member variable to methods of a specific format). At the end of the day, though, you're not going to be able to do something the compiler doesn't accept in the language and get it to compile.

Short version: Can't do it. There is no native support for this, c++ is statically typed and the compiler has to know the structure of each object to be manipulated.

Recommendation: Use an embedded interperter. And don't write your own (see below), get one that is already working and debugged.


What you can do: Implement just enough interperter for your needs.

It would be simple enough to setup the class with a data member like

std::vector<void*> extra_data;

to which you could attach arbitrary data at run-time. The cost of this is that you will have to manage that data by hand with methods like:

size_t add_data_link(void *p); // points to existing data, returns index
size_t add_data_copy(void *p, size_t s) // copies data (dispose at
                                        // destruction time!), returns 
                                        // index 
void* get_data(size_t i); //...

But that is not the limit, with a little more care, you could associate the arbitrary data with a name and you can continue to elaborate this scheme as far as you wish (add type info, etc...), but what this comes down to is implementing an interperter to take care of your run-time flexibility.

No -- C++ does not support any manipulation of the type system like this. Even languages with some degree of runtime reflection (e.g. .NET) would not support exactly this paradigm. You would need a much more dynamic language to be able to do it.

I was looking at this and I did a little search around, this code snippet obtained from : Michael Hammer's Blog seems to be a good way to do this, by using boost::any

First you define a structure that defines an std::map that contains a key (i.e. variable name) and the value. A function is defined to ad the pair and set it along with a function to get the value. Pretty simple if you ask me, but it seems a good way to start before doing more complex things.

struct AnyMap {
  void addAnyPair( const std::string& key , boost::any& value );

  template<typename T>
  T& get( const std::string key ) {
    return( boost::any_cast<T&>(map_[key]) );
  }

  std::map<const std::string, boost::any> map_;
};

void AnyMap::addAnyPair( const std::string& key , boost::any& value ) {
  map_.insert( std::make_pair( key, value ) );
}

Bottom line, this is a hack, since C++ is strict type-checking language, and thus monster lie within for those that bend the rules.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top