iha*_*ato 5 c++ g++ multiple-inheritance
在像下面这样的“经典”菱形问题中(virtual前面public D、后面class C和没有没有class B),可以使用名称范围运算符来解决歧义::,例如在 class 的构造函数中A:
/*
* D D D
* / \ which without 'virtual' | |
* B C is actually: B C
* \ / \ /
* A A
*/
#include <iostream>
using namespace std;
class D { public: char d = 'D';};
class C : public D { public: char c = 'C';};
class B : public D { public: char b = 'B';};
class A : public B, public C { public: char a = 'A'; A();};
A::A() {
cout << B::d; //This works! B's d, inherited from D.
cout << C::d; //This works! C's d, inherited from D.
//cout << D::d; //This doesn't work (ambiguous)
//cout << B::D::d; //Doesn't work either though.
//cout << C::D::d; //Doesn't work either though.
}
int main() {
A a;
cout << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
现在考虑这样的双钻石:
/*
* G G G G G
* / \ | | | |
* E F E F E F
* \ / \ / \ /
* D D D
* / \ which without 'virtual' | |
* B C is actually: B C
* \ / \ /
* A A
*/
#include <iostream>
using namespace std;
class G { public: char g = 'G';};
class E : public G { public: char e = 'E';};
class F : public G { public: char f = 'F';};
class D : public E, public F { public: char d = 'D';};
class C : public D { public: char c = 'C';};
class B : public D { public: char b = 'B';};
class A : public B, public C { public: char a = 'A'; A();};
A::A() {
cout << /* How do I reach any of the two e's or f's
or any of the four g's?*/
}
int main() {
A a;
cout << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
究竟如何到达从 E、F 和 G 继承的字段?实际上对我来说最合乎逻辑的是以下内容。
cout << B::D::d;
cout << B::D::E::e;
cout << B::D::F::f;
cout << B::D::E::G::g;
cout << B::D::F::G::g;
cout << C::D::d;
cout << C::D::E::e;
cout << C::D::F::f;
cout << C::D::E::G::g;
cout << C::D::F::G::g;
Run Code Online (Sandbox Code Playgroud)
但是(使用 g++)它们都会产生形式为 的错误'X' is an ambiguous base of 'A'.。
有人可以解释为什么这不起作用以及这样做的正确方法是什么?我错过了什么?
这不起作用的原因:
cout << B::D::d;
Run Code Online (Sandbox Code Playgroud)
是因为:作用域解析是左右关联的;这在某种意义上类似于(B::D) :: d,尽管这里实际上不允许使用括号。这样限定查找B::D就解决了,找到了类型D。只有一种类型称为D ,没有单独的类型A::D和B::D。同一类型可以在多个范围中找到。
因此,您得到的等价物D::d是不明确的,因为有多个路径到达类型的基础D。
要获得所需的变量,您可能必须使用一系列强制转换,例如:
cout << static_cast<G&>(static_cast<E&>(static_cast<D&>(static_cast<B&>(*this)))).g;
Run Code Online (Sandbox Code Playgroud)
在 C 风格语法中,您可以使用((G&)(E&)(D&)(B&)(*this)).g,尽管这很危险,就像您在类排序中犯了错误一样,您将得到 areinterpret_cast而不是 a static_cast,这可能会发生故障。
实际上,在这种情况下,您可以省略该D步骤,因为 aB具有唯一的E基数:
cout << static_cast<G&>(static_cast<E&>(static_cast<B&>(*this))).g;
Run Code Online (Sandbox Code Playgroud)
甚至:
cout << static_cast<B&>(*this).E::g;
Run Code Online (Sandbox Code Playgroud)
E::g因为一旦我们到达,就有一个独特的B。
也可以使用dynamic_cast代替static_cast,我愿意接受关于哪种风格更好的评论:)