当c ++遇到钻石问题时会发生什么

时间:2012-10-16 21:27:28

标签: c++ multiple-inheritance

来自java背景我从来没有遇到过钻石问题,其中多重继承会导致覆盖问题,详见http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem

但是如果出现这个问题,c ++运行时会抱怨或者是否随机调用超类方法的实现?

我已经阅读了文章中的“缓解”部分,但没有完全理解它。

2 个答案:

答案 0 :(得分:2)

编译器将通过诊断任何歧义来捕获遇到钻石问题的程序。

一种解决方案是消除歧义。使用显式名称限定引用成员时可以这样做:

struct B {
    int bar;
};

struct D1 : B {};
struct D2 : B {};

struct E : D1, D2 {};

int main() {
    E e;
    e.D1::bar = 1; // explicitly set D1::bar, not D2::bar.
}

或者,如果您想要访问基础子对象,如:B *b = new E;您是否想要D1或D2的基础子对象是不明确的。使用显式强制转换为其中一种中间类型可以解决歧义。

B *b = static_cast<D2*>(new E);

另请注意,从B *到E *的向下转换不可能是静态的;编译器不知道指向哪个B,因此它不会静态地知道如何调整指针以返回E.这就是dynamic_cast必要的地方。

E *e = new E;
B *b1 = static_cast<D1*>(e);
B *b2 = static_cast<D2*>(e);
assert(b1 != b2);
assert(dynamic_cast<E*>(b1) == dynamic_cast<E*>(b2));
assert(e == dynamic_cast<E*>(b1));

另一个解决方案是回避虚拟继承的问题,从而避免使用相同类型的多个基础子对象。

struct B {
    virtual void foo() = 0;
    virtual ~B() = default;
    int bar;
};

struct D1 : virtual B {};
struct D2 : virtual B {};

struct E : D1, D2 {
    virtual void foo() override {
        bar = 1; // no ambiguity because there's only a single B base sub-object
    }
};

答案 1 :(得分:1)

编译器捕获错误。 http://www.parashift.com/c%2B%2B-faq-lite/mi-diamond.html

提供了一个示例
class Base {
public:
protected:
  int data_;
};

class Der1 : public Base {  };

class Der2 : public Base {  };

class Join : public Der1, public Der2 {
public:
  void method()
  {
      data_ = 1; //g++ error: reference to ‘data_’ is ambiguous
  }
};

int main()
{
  Join* j = new Join();
  Base* b = j; //g++ error: ‘Base’ is an ambiguous base of ‘Join’
}