Consider the following setting.
Base class:
class Thing { int f1; int f2; Thing(NO_INIT) {} Thing(int n1 = 0, int n2 = 0): f1(n1),f2(n2) {} virtual ~Thing() {} virtual void doAction1() {} virtual const char* type_name() { return "Thing"; } }
And derived classes that differ only in the implementation of the above methods:
class Summator { Summator(NO_INIT):Thing(NO_INIT) {} virtual void doAction1() override { f1 += f2; } virtual const char* type_name() override { return "Summator"; } } class Substractor { Substractor(NO_INIT):Thing(NO_INIT) {} virtual void doAction1() override { f1 -= f2; } virtual const char* type_name() override { return "Substractor"; } }
The task that I require requires the ability to change the class (VTBL in this case) of existing objects on the fly. This is called a dynamic subclass if I'm not mistaken.
So, I came up with the following function:
// marker used in inplace CTORs struct NO_INIT {}; template <typename TO_T> inline TO_T* turn_thing_to(Thing* p) { return ::new(p) TO_T(NO_INIT()); }
which does just that - it uses inplace new to create one object instead of another. Effectively, it simply changes the vtbl pointer in objects. Thus, this code works as expected:
Thing* thing = new Thing(); cout << thing->type_name() << endl; // "Thing" turn_thing_to<Summator>(thing); cout << thing->type_name() << endl; // "Summator" turn_thing_to<Substractor>(thing); cout << thing->type_name() << endl; // "Substractor"
The only serious problems I encounter are that a) each derived class must have special constructors, such as Thing(NO_INIT) {} , which should not do anything. And b) if I want to add elements such as std :: string to Thing, they will not work - only types that have NO_INIT constructors are allowed as Thing members.
Question: is there a better solution for such a dynamic subclass that solves problems "a" and "b"? I have a feeling that std :: move semantic might help solve "b" somehow, but I'm not sure.
Here is the ideone code.