C++ 在虚拟功能的背景下,什么是优势? 代码示例:

C++ 在虚拟功能的背景下,什么是优势? 代码示例:,c++,c++11,language-lawyer,virtual-functions,virtual-inheritance,C++,C++11,Language Lawyer,Virtual Functions,Virtual Inheritance,考虑以下菱形层次结构: 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 cal

考虑以下菱形层次结构:

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。10.2第10页明确确认了这一点:

[注意:使用虚拟基类时,可以通过 未通过隐藏声明的子对象晶格。这不是歧义。相同的 与非虚拟基类一起使用是不明确的;在这种情况下,该名称没有唯一的实例 隐藏所有其他内容。-结束注释][示例:

此外,对于一个相关问题,他对该问题作了详尽的解释

问题是: 我不明白的是,上面提到的引用是如何与虚拟函数
f
相关的。
f
没有隐藏名称,是吗?只涉及重写,10.3 p.2的内容如下:

类对象S的虚拟成员函数C::vf是最终的 重写,除非S是基的最派生类(1.8) 类子对象(如果有)声明或继承另一个成员函数 在派生类中,如果 基类子对象在程序中有多个最终重写器 他身体不好

现在,在我看来,虚拟函数
f
完全符合没有最终重写器的定义,并且程序的格式应该是错误的。但事实并非如此。或者是这样吗?MSVC编译得很好,但有以下警告:

警告C4250:“D”:通过支配继承“B::B::f”

老实说,我以前从来没有遇到过“支配”这个词。当我在标准中搜索它时,它在索引中只出现一次,并将我引述到我第一个引用的章节。而且,正如我已经提到的,该引用似乎只涉及名称隐藏,而不是虚拟函数重写

问题:
  • f
    在D中是否有多个最终重写器
  • 在这种情况下,支配规则适用吗?它是如何遵循标准的

    • 我再次引用
      [10.3]/2

      类对象
      S
      的虚拟成员函数
      C::vf
      是最终重写器,除非其中
      S
      的最派生类(1.8)是基类子对象(如果有)声明或继承另一个重写
      vf
      的成员函数。在派生类中,如果基类子对象的虚拟成员函数具有多个最终重写器,则程序格式错误

      因此,在您的示例中,
      A::f
      不是最终重写器,因为
      D
      (最派生的类)继承了覆盖它的
      B::f
      B::f
      是最终重写器,因此它被称为

      如果有多个最终重写器(例如,如果
      C
      也重写了
      f
      ),则程序的格式将不正确,但只有一个,因此一切正常

      Clang和GCC编译这个


      回答你的问题,准确地描述了你的情况,所谓支配,显然是指
      [10.3]/2

      中描述的行为
      C::f()
      调用了什么?-它不算作虚拟成员函数?(从a继承)@MattMcNabb我不明白这个问题。类
      C
      不会覆盖
      f
      。您可以调用
      C::f()
      C
      继承
      A
      ,而无需overriding@MattMcNabb你是说
      dd;dc::f();
      ?是的,它将根据
      5.2.2/1
      调用
      A::f()
      (MattMcNabb通常是通过超载解析规则发现的)@:没有函数<代码> C::f>代码>但是在代码< > >代码>范围内查找<代码> f>代码>查找<代码>::f>代码>在C++中包含一个包含<代码> fo>代码>的范围,在该范围内可以找到<代码> fo>代码>。