请考虑以下设置。

基类:

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());
    }

就是这样做的-它使用就地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之类的成员,它们将不起作用-只有具有NO_INIT构造函数的类型才被允许作为Thing的成员。

问题:对于此类动态子类,是否存在更好的解决方案来解决“a”和“b”问题?我觉得std::move语义可能会以某种方式帮助解决“b”问题,但不确定。

这是代码的ideone

最佳答案

(已在RSDN上http://rsdn.ru/forum/cpp/5437990.1回答)

有一个棘手的方法:

struct Base
{
    int x, y, z;
    Base(int i) : x(i), y(i+i), z(i*i) {}
    virtual void whoami() { printf("%p base %d %d %d\n", this, x, y, z); }
};

struct Derived : Base
{
    Derived(Base&& b) : Base(b) {}
    virtual void whoami() { printf("%p derived %d %d %d\n", this, x, y, z); }
};

int main()
{
    Base b(3);
    Base* p = &b;

    b.whoami();
    p->whoami();

    assert(sizeof(Base)==sizeof(Derived));
    Base t(std::move(b));
    Derived* d = new(&b)Derived(std::move(t));

    printf("-----\n");
    b.whoami(); // the compiler still believes it is Base, and calls Base::whoami
    p->whoami(); // here it calls virtual function, that is, Derived::whoami
    d->whoami();
};

当然是UB。

10-07 19:29
查看更多