考虑以下钻石层次结构:
struct A
{
virtual void f(){}
void g(){}
};
struct B : virtual A
{
virtual void f() override{}
void g(){}
};
struct C : virtual A
{
};
struct D: B, C
{
};
int main()
{
D d;
d.f(); //B::f is called
d.g(); //B::g is called
}
就非虚拟函数g
而言,一切都很清楚:名称B::g
隐藏A::g
,即使名称A::g
可以在没有通过C
隐藏。没有含糊之处。调用B::g
。 The standard在10.2 p.10中明确证实了这一点:
[注意:当使用虚拟基类时,可以沿着通过的路径到达隐藏声明 不通过隐藏声明的子对象网格。这不是含糊不清的。相同的 使用非虚拟基类是一种模糊性;在这种情况下,没有唯一的名称实例 隐藏所有其他人。 - 尾注] [例子:
此外,this answer对相关问题提供了对此问题的详尽解释。
我不明白上面提到的引用与虚函数f
的关系。 f
没有涉及名称隐藏,是吗?只涉及覆盖,10.3 p.2读取:
类对象S的虚拟成员函数C :: vf是final 除非最大的派生类(1.8)是S的基础,否则覆盖 class subobject(如果有)声明或继承另一个成员函数 这会覆盖vf。在派生类中,如果是虚拟成员函数 基类子对象有多个最终覆盖程序 是不正确的。
现在,在我看来,虚函数f
完全符合具有最终覆盖的不的定义,并且程序应该是格式错误的。但事实并非如此。或者是吗? MSVC编译得很好,有以下警告:
警告C4250:' D' :继承' B :: B :: f'通过支配地位
说实话,我从来没有遇到过这样的术语"支配地位"之前。当我在标准中搜索它时,它在索引中只出现一次,并引用我的第一个引用来自的章节。并且,正如我已经提到的,引用似乎只与名称隐藏而不是虚函数覆盖有关。
f
在D中有多个最终覆盖? 答案 0 :(得分:5)
我再次引用[10.3]/2
:
类对象
C::vf
的虚拟成员函数S
是最终覆盖,除非S
为基数的派生类(1.8)最多class subobject(如果有)声明或继承覆盖vf
的另一个成员函数。在派生类中,如果基类子对象的虚拟成员函数具有多个最终覆盖,则程序格式不正确。
因此,在您的示例中,A::f
不是最终的覆盖者,因为D
(派生程度最高的类)继承了覆盖它的B::f
。 B::f
是最后的覆盖者,所以它被调用。
如果有多个最终覆盖者(例如,如果C
也覆盖f
),该程序将是格式错误的,但只有一个,所以一切都很好。
Clang和GCC编译此without a single warning。
回答你的问题,the documentation on C4250 warning完全描述了你的情况,并且通过支配它显然意味着[10.3]/2
中描述的行为。