关于多重继承和歧义
About multiple inheritance and ambiguity
在下面的例子中:
class A {
public:
virtual void f() { cout << "a" << endl; }
virtual void h() { cout << "A" << endl; }
};
class s1 : public A {
public:
virtual void f() { cout << "s1" << endl; }
};
class s2 : public A {
public:
virtual void h() { cout << "s2" << endl; }
};
class GS : public s1, public s2 {
public:
};
int main()
{
s1 *q = new GS;
q->h();//no problem
GS a;
a.h();//error
}
为什么 a.h();
给出了歧义错误而 q->h();
却没有?
*q
没有一个 GS
的实例会导致同样的歧义问题吗?
好的,这是因为当编译器计算 q->h() 时,q 在其范围内只有一个名为 'h' 的函数,因为它是 s1 类型。
当编译器计算 a.h() 时,a 在其范围内有两个名为 'h' 的函数。一个来自 s1,一个来自 s2。
编译器不知道您要使用哪一个,因此会抛出错误。
*q
不会给出歧义错误,因为它的类型是 s1*
。这意味着编译器将调用 s1::h
,这是明确的。
因为你的指针是s1
类型所以编译器知道调用h()
(继承自class A
)。尝试使用 GS
类型的指针,您也会收到指针错误。在 GS
的情况下,您是从 s1
和 s2
继承的,两个 class 都是从 A
继承的,因此 [= 的多个 (2) 定义11=] 被发现是模棱两可的。这是 dreaded diamond.
名称查找基于静态类型而非动态类型。 (而且必须如此,因为它发生在编译时而不是 运行 时。)
您使用多重继承导致 A
的两个实例出现在 GS
中。当您使用 S1 *q
访问 GS
实例时,它跟随与 S1
关联的 A
实例。由于 S1
没有实现 h()
,q->h()
的输出将是 A
本身提供的实现。
如果你想q->h()
使用S2
提供的实现,那么你需要使用虚拟继承来创建钻石。这样做也会消除使用 a.h()
时的歧义,因为虚拟继承只会导致 A
的一个实例出现在 GS
.
中
class s1 : virtual public A {
public:
virtual void f() { cout << "s1" << endl; }
};
class s2 : virtual public A {
public:
virtual void h() { cout << "s2" << endl; }
};
在下面的例子中:
class A {
public:
virtual void f() { cout << "a" << endl; }
virtual void h() { cout << "A" << endl; }
};
class s1 : public A {
public:
virtual void f() { cout << "s1" << endl; }
};
class s2 : public A {
public:
virtual void h() { cout << "s2" << endl; }
};
class GS : public s1, public s2 {
public:
};
int main()
{
s1 *q = new GS;
q->h();//no problem
GS a;
a.h();//error
}
为什么 a.h();
给出了歧义错误而 q->h();
却没有?
*q
没有一个 GS
的实例会导致同样的歧义问题吗?
好的,这是因为当编译器计算 q->h() 时,q 在其范围内只有一个名为 'h' 的函数,因为它是 s1 类型。
当编译器计算 a.h() 时,a 在其范围内有两个名为 'h' 的函数。一个来自 s1,一个来自 s2。
编译器不知道您要使用哪一个,因此会抛出错误。
*q
不会给出歧义错误,因为它的类型是 s1*
。这意味着编译器将调用 s1::h
,这是明确的。
因为你的指针是s1
类型所以编译器知道调用h()
(继承自class A
)。尝试使用 GS
类型的指针,您也会收到指针错误。在 GS
的情况下,您是从 s1
和 s2
继承的,两个 class 都是从 A
继承的,因此 [= 的多个 (2) 定义11=] 被发现是模棱两可的。这是 dreaded diamond.
名称查找基于静态类型而非动态类型。 (而且必须如此,因为它发生在编译时而不是 运行 时。)
您使用多重继承导致 A
的两个实例出现在 GS
中。当您使用 S1 *q
访问 GS
实例时,它跟随与 S1
关联的 A
实例。由于 S1
没有实现 h()
,q->h()
的输出将是 A
本身提供的实现。
如果你想q->h()
使用S2
提供的实现,那么你需要使用虚拟继承来创建钻石。这样做也会消除使用 a.h()
时的歧义,因为虚拟继承只会导致 A
的一个实例出现在 GS
.
class s1 : virtual public A {
public:
virtual void f() { cout << "s1" << endl; }
};
class s2 : virtual public A {
public:
virtual void h() { cout << "s2" << endl; }
};