基类引用 - 为其指定其他类型

时间:2012-06-16 17:38:00

标签: c++ reference

以下示例会发生什么?

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

我知道引用没有重新分配。 x仍然引用d,但是您如何将d2分配给d

更多:

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不是......为什么?

3 个答案:

答案 0 :(得分:11)

x引用B的{​​{1}}基类子对象。作业d slices来自x = d2的{​​{1}}基础子对象,并将其值分配给B的子对象。

通常不会故意这样做。

修改

  

似乎x.x已更新,但vftable不是......为什么?

这就是赋值运算符d2的作用。 C ++中的基类完全没有意识到它们是基类。此外,在其生命周期内不能改变对象的类型。最接近的替代方案是C ++ 11的d,它可以将B::operator=内的旧std::move对象转移到新的B对象中。然后你会破坏旧的对象。

答案 1 :(得分: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;
  }
};

答案 2 :(得分:1)

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