问题描述
我已经浏览了几十个多重继承问题,但没有找到这个问题的答案。
我明白为什么这不会编译:
struct B{
virtual void f(){
printf("B");
}
};
struct C1 : virtual B{
void f() override{
printf("C1");
}
};
struct C2: virtual B{
void f() override{
printf("C2")
}
};
struct D: C1,C2{
};
因为无法确定哪个 f
应该在 B
的 vtable 中。
然而,我很惊讶地看到这段代码会编译:
struct B{
virtual void f(){
printf("B");
}
};
struct C1 : virtual B{
void f() override{
printf("C1");
}
};
struct C2: virtual B{
};
struct D: C1,C2{
};
我的(错误的)直觉是我们仍然有两条路径从 D
到 B
并且在每一条路径中,最后一个位置 f
被覆盖是不同的 - 在一条路径中它在 { {1}} 并且在一个路径中它在 C1
中,但这确实可以编译。
为什么这不会引起歧义?
解决方法
因为 C1::f1 覆盖 B::f1,它将优先用于任何具有 C1 动态类型或任何子类的对象。
在模棱两可的情况下,虽然 C1::f1 和 C2::f1 都覆盖了 B::f1,但它们并不相互覆盖,所以歧义是在它们之间——事实上它们都覆盖了一个共同的基函数无关紧要。