来自 java 背景,我从未遇到过多重继承可能导致覆盖问题的菱形问题,如http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem中详细描述的那样
但是如果出现这个问题,c++ 运行时会抱怨还是随机调用超类方法的哪个实现?
我已经阅读了文章的“缓解”部分,但没有完全理解。
来自 java 背景,我从未遇到过多重继承可能导致覆盖问题的菱形问题,如http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem中详细描述的那样
但是如果出现这个问题,c++ 运行时会抱怨还是随机调用超类方法的哪个实现?
我已经阅读了文章的“缓解”部分,但没有完全理解。
编译器将通过诊断任何歧义来捕获遇到菱形问题的程序。
一种解决方案是消除歧义。这可以在使用显式名称限定来引用成员时完成:
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
}
};
该错误被编译器捕获。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’
}