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"; }
}
而仅通过实现上述方法有所不同的派生类:
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"; }
}
我需要一个能够在运行时改变现有对象类(在这种情况下是VTBL)的能力。如果我没记错的话,这被称为动态子类化。
所以,我想出了以下函数:
// 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());
}
这段代码使用了inplace new
来构造一个对象来代替另一个对象,从而实现了相应的功能。实际上,这只是改变了对象中的vtbl指针。因此,这段代码可以正常工作:
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"
我对这种方法唯一的主要问题是,a) 每个派生类都必须有特殊构造函数,例如
Thing(NO_INIT) {}
,它们什么也不做。b) 如果我想向Thing添加像std::string这样的成员,它们将无法工作 - 只允许作为Thing成员的具有NO_INIT构造函数的类型。问题:是否有更好的解决动态子类化的方法来解决'a'和'b'问题?我觉得std::move语义可能会在某种程度上解决'b'问题,但不确定。
这里是代码的ideone。