双钻到达远方基地class的方法是什么?
What is the way to reach a field or a method of a far away base class in a double diamond?
在 "classical" 钻石问题如下
([=15= 前面没有 virtual
的那个,
在 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;
}
现在考虑像这样的双钻石:
/*
* 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;
}
究竟怎样才能达到继承自 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;
但是(使用 g++)它们都会产生 'X' is an ambiguous base of 'A'.
.
形式的错误
有人可以解释为什么这不起作用吗?正确的方法是什么?我错过了什么?
让我们从您收到的错误开始。 'X' is an ambiguous base of 'A'.
编译器告诉您在获取您为 std::cout 选择的对象的父级时有一个 ambiguity/uncertainty。没有指定抽象基础类,你的继承结构是正确的。
/*
* 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
*/
现在问题实际上出在您要写入标准输出的内容中。
这是你写的:
cout << B::D::d;
cout << B::D::E::e;
cout << B::D::F::e; // When does F inherit from E and get member variable e?
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::e; // When does F inherit from E???
cout << C::D::E::G::g;
cout << C::D::F::G::g;
我还没有用 g++ 测试这个(我使用的是 MSVC++),但是这个有效:
A::A() {
std::cout << B::b
<< B::D::d
<< B::D::E::e
<< B::D::F::f
<< B::D::E::G::g << std::endl;
/* How do I reach any of the two e's or f's
or any of the four g's?*/
}
干杯!
编辑:
这是您在 MSVC++ 中遇到的错误
这是它在 MSVC++ 中工作的一些证明”:
现在在 g++ 中:
#include <iostream>
#include <stdio.h>
using namespace std;
class G { public: char g = 'G';};
class E : virtual public G { public: char e = 'E';};
class F : virtual public G { public: char f = 'F';};
class D : public E, public F { public: char d = 'D';};
class C : virtual public D { public: char c = 'C';};
class B : virtual public D { public: char b = 'B';};
class A : public B, public C { public: char a = 'A'; A();};
A::A() {
std::cout << A::a
<< A::B::b
<< A::B::D::d
<< A::B::D::E::e
<< A::B::D::F::f
<< A::B::D::E::G::g
<< std::endl;
}
int main() {
A a;
cout << endl;
return 0;
}
这应该有效。
这不起作用的原因:
cout << B::D::d;
是因为:作用域解析是左右关联的;这在某种意义上类似于 (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;
在 C 风格的语法中,您可以使用 ((G&)(E&)(D&)(B&)(*this)).g
,尽管这很危险,因为如果您在 class 顺序中犯了错误,您将得到 reinterpret_cast
而不是 static_cast
可能会出现故障。
实际上在这种情况下您可以省略 D
步骤,因为 B
具有唯一的 E
基数:
cout << static_cast<G&>(static_cast<E&>(static_cast<B&>(*this))).g;
甚至:
cout << static_cast<B&>(*this).E::g;
因为一旦我们在 B
.
,就有一个唯一的 E::g
也可以使用 dynamic_cast
而不是 static_cast
,我愿意接受关于哪种样式更好的评论:)
在 "classical" 钻石问题如下
([=15= 前面没有 virtual
的那个,
在 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;
}
现在考虑像这样的双钻石:
/*
* 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;
}
究竟怎样才能达到继承自 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;
但是(使用 g++)它们都会产生 'X' is an ambiguous base of 'A'.
.
有人可以解释为什么这不起作用吗?正确的方法是什么?我错过了什么?
让我们从您收到的错误开始。 'X' is an ambiguous base of 'A'.
编译器告诉您在获取您为 std::cout 选择的对象的父级时有一个 ambiguity/uncertainty。没有指定抽象基础类,你的继承结构是正确的。
/*
* 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
*/
现在问题实际上出在您要写入标准输出的内容中。 这是你写的:
cout << B::D::d;
cout << B::D::E::e;
cout << B::D::F::e; // When does F inherit from E and get member variable e?
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::e; // When does F inherit from E???
cout << C::D::E::G::g;
cout << C::D::F::G::g;
我还没有用 g++ 测试这个(我使用的是 MSVC++),但是这个有效:
A::A() {
std::cout << B::b
<< B::D::d
<< B::D::E::e
<< B::D::F::f
<< B::D::E::G::g << std::endl;
/* How do I reach any of the two e's or f's
or any of the four g's?*/
}
干杯!
编辑:
这是您在 MSVC++ 中遇到的错误
这是它在 MSVC++ 中工作的一些证明”:
现在在 g++ 中:
#include <iostream>
#include <stdio.h>
using namespace std;
class G { public: char g = 'G';};
class E : virtual public G { public: char e = 'E';};
class F : virtual public G { public: char f = 'F';};
class D : public E, public F { public: char d = 'D';};
class C : virtual public D { public: char c = 'C';};
class B : virtual public D { public: char b = 'B';};
class A : public B, public C { public: char a = 'A'; A();};
A::A() {
std::cout << A::a
<< A::B::b
<< A::B::D::d
<< A::B::D::E::e
<< A::B::D::F::f
<< A::B::D::E::G::g
<< std::endl;
}
int main() {
A a;
cout << endl;
return 0;
}
这应该有效。
这不起作用的原因:
cout << B::D::d;
是因为:作用域解析是左右关联的;这在某种意义上类似于 (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;
在 C 风格的语法中,您可以使用 ((G&)(E&)(D&)(B&)(*this)).g
,尽管这很危险,因为如果您在 class 顺序中犯了错误,您将得到 reinterpret_cast
而不是 static_cast
可能会出现故障。
实际上在这种情况下您可以省略 D
步骤,因为 B
具有唯一的 E
基数:
cout << static_cast<G&>(static_cast<E&>(static_cast<B&>(*this))).g;
甚至:
cout << static_cast<B&>(*this).E::g;
因为一旦我们在 B
.
E::g
也可以使用 dynamic_cast
而不是 static_cast
,我愿意接受关于哪种样式更好的评论:)