tags:

views:

1115

answers:

5

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 !

+4  A: 

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.

Mark Ransom
A: 

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.

Rob Walker
+1  A: 

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.

dmckee
Could you please post a little snippet that works ?
Vhaerun
paercebal's answer is in a similar vein, and uses more c++ idiom. Mine looks a lot like a solution crammed into a class, because that is what it is...
dmckee
+3  A: 

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.

Nick
+11  A: 

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.

paercebal
Thank you paercebal ! Would it be possible to overload -> to achieve the effect I was talking about ?
Vhaerun
No, sorry, because the "newField" you're adding has not been compiled, only created in runtime, and thus, it can't be used in code symbols, only in strings (there, despite some drawbacks, the operator[] is a shiny syntactic sugar).
paercebal