我在在线测试中遇到了以下c ++代码。
#include <iostream>
class A
{
public:
A(int n = 2) : m_n(n) {}
public:
int get_n() const { return m_n; }
void set_n(int n) { m_n = n; }
private:
int m_n;
};
class B
{
public:
B(char c = 'a') : m_c(c) {}
public:
char get_c() const { return m_c; }
void set_c(char c) { m_c = c; }
private:
char m_c;
};
class C
: virtual public A
, public B
{ };
class D
: virtual public A
, public B
{ };
class E
: public C
, public D
{ };
int main()
{
E e;
C &c = e;
D &d = e;
std::cout << c.get_c() << d.get_n();
c.set_n(3);
d.set_c('b');
std::cout << c.get_c() << d.get_n() << std::endl;
return 0;
}
代码输出a2a3,但我不明白。为什么这个运行在第一位不是B类方法不明确? E类也几乎没有继承。
答案 0 :(得分:5)
如果您尝试e.get_c()
,那将是模棱两可的。
但是,C
和D
接口每个只包含一个B
,并且彼此一无所知。
答案 1 :(得分:3)
由于c
的类型为C&
且d
的类型为D&
,因此没有歧义 - C
和D
只有一个{ {1}}子对象。
(B
和c
字面上引用d
的相应子对象 - 它们不是指“e
,而是指不同类型”。)< / p>
输出为“a2a3”而不是“a2b3”或“a2a2”的原因是e
是虚拟继承的,因此A
中只有一个A
子对象,因此只有一个E
成员。
n
和C
子对象各有一个D
子对象,B
修改d.set_c('b');
中的{@}}但不修改d
中的对象。 }。
答案 2 :(得分:1)
您通过C
和D
引用来评估c
和d
类的方法,没有歧义。试试这个
std::cout << e.C::get_c() << e.C::get_n() << std::endl;
std::cout << e.D::get_c() << e.D::get_n() << std::endl;
//line below will not compile because here access 'get_c' is ambiguous
//std::cout << e.get_c() << e.get_n() << std::endl;
在这里,您将直接通过C
实例访问D
和e
类的方法。现在最后一行是不明确的,因为调用了e.get_c()
,您必须指定C::
或D::
前缀来解决有关C
或D
的歧义方法
std::cout << e.C::get_c() << e.get_n() << std::endl;
std::cout << e.D::get_c() << e.get_n() << std::endl;
注意:不需要在get_n()之前放置前缀,因为A
是一个虚拟基类,在继承树中的C
和D
之间进行了剪切。