12

下面的例子会发生什么?

struct B { };
struct D1 : B  { };
struct D2 : B  { };
int main()
{
    D1 d;
    D2 d2;
    B& x = d;
    x = d2;
}

我知道引用没有重新分配。x还是指d,可是那又怎么能指派d2d呢?

多一点:

struct B
{
    B () { x = 0; }
    int x;
    virtual void foo () { cout << "B" << endl; }
};
struct D1 : B
{
    D1 () { x = 1; }
    virtual void foo () { cout << "D1" << endl; }
};
struct D2 : B
{
    D2 () { x = 2; }
    virtual void foo () { cout << "D2" << endl; }
};

int main()
{
D1 d;
D2 d2;
B& x = d;
x.foo();   //D1
               //x.x is 1 here
x = d2;
x.foo();   //also D1
               //but x.x is 2 here
}

似乎x.x已更新,但 vftable 没有……为什么?

4

3 回答 3

11

x指的是 的基B子对象d赋值从 中x = d2 B基础子对象d2并将其值分配给 的子对象d

这通常不是故意的。

编辑:

好像 xx 更新了,但是 vftable 没有……为什么?

这就是赋值运算符的B::operator=作用。C++ 中的基类完全不知道它们是基类。此外,对象的类型在其生命周期内永远无法更改。最接近的替代方案是 C++11 std::move,它可以将 a 中的旧B对象D1转换为新D2对象。然后,您将销毁旧对象。

于 2012-06-16T17:44:14.530 回答
3

如果需要,您可以自己实现 = 并通过检查适当的具体类型(或给出错误)“避免”切片。请参阅下面的错误示例。

struct B { 
  virtual B& operator = (B& b) = 0;
};
struct D1 : B  { 
  D1& operator = (B& b) {
    if ( dynamic_cast<D1*>(&b) == 0 ) {
      cerr << "Cannot assign non D1 to D1" << endl;
      exit(255);
    }
    // handle the assignments
    return *this;
  }
};
struct D2 : B  { 
  int c;
  D2& operator = (B& b) {
    if ( dynamic_cast<D2*>(&b) == 0 ) {
      cerr << "Cannot assign non D2 to D2" << endl;
      exit(255);
    }
    // handle the assignments
    return *this;
  }
};
于 2012-06-16T18:01:31.807 回答
1

在您的情况下,当您以这种方式分配成员时,不属于 Base 类的成员将被切片。这意味着,在这种情况下,它就像您将一个基类对象分配给另一个一样被复制。

于 2012-06-16T17:44:42.440 回答