代码之家  ›  专栏  ›  技术社区  ›  squelart

为什么派生类中的重写方法可选“virtual”?

  •  15
  • squelart  · 技术社区  · 15 年前

    当方法声明为 virtual 在类中,将自动考虑派生类中的重写 事实上的 另外,C++语言也给出了这个关键字 事实上的 在这种情况下是可选的:

    class Base {
        virtual void f();
    };
    class Derived : public Base {
        void f(); // 'virtual' is optional but implied.
    };
    

    我的问题是:为什么 事实上的 可选的?

    我知道不一定要告诉编译器这一点,但我认为如果编译器强制执行这样的约束,开发人员会受益。

    例如,有时当我读到别人的代码时,我想知道一个方法是否是虚拟的,我必须跟踪它的超类来确定这一点。以及一些编码标准( Google )“必须”把 事实上的 所有子类中的关键字。

    5 回复  |  直到 15 年前
        1
  •  11
  •   Kornel Kisielewicz    15 年前

    是的,在这种情况下,让编译器强制使用虚拟机会更好,我同意这是一个为向后兼容性而维护的设计错误。

    然而,有一个技巧如果没有它是不可能的:

    class NonVirtualBase {
      void func() {};
    };
    
    class VirtualBase {
      virtual void func() = 0;
    };
    
    template<typename VirtualChoice>
    class CompileTimeVirtualityChoice : public VirtualChoice {
      void func() {}
    };
    

    根据以上内容,我们可以选择编译时,我们是否希望func的虚拟性:

    CompileTimeVirtualityChoice<VirtualBase> -- func is virtual
    CompileTimeVirtualityChoice<NonVirtualBase> -- func is not virtual
    

    …但我同意,这对寻找一个函数的虚拟性的成本来说是一个微小的好处,而我自己,我总是尝试在任何适用的地方输入虚拟。

        2
  •  6
  •   Dennis Zickefoose    15 年前

    作为一个相关的注释,在C++ 0x中,您可以通过新的属性语法来强制执行显式重写。

    struct Base {
      virtual void Virtual();
      void NonVirtual();
    };
    
    struct Derived [[base_check]] : Base {
      //void Virtual(); //Error; didn't specify that you were overriding
      void Virtual [[override]](); //Not an error
      //void NonVirtual [[override]](); //Error; not virtual in Base
      //virtual void SomeRandomFunction [[override]](); //Error, doesn't exist in Base
    };
    

    还可以通过 [[hiding]] 属性。它使您的代码更加冗长,但在编译时它会捕获许多恼人的错误,就像您这样做了一样。 void Vritual() 而不是 void Virtual() 当您想要覆盖一个现有的函数时,最终会引入一个全新的函数。

        3
  •  3
  •   valdo    15 年前

    设计上的弱点,我同意。 我也认为那是 真正地 很好,如果有两种不同的语法:

    1. 声明虚函数。即在派生类中可以被重写的函数。(这实际上在vtable中添加了一个新的函数条目。)
    2. 重写派生类中的虚函数。

    在重写函数时,用当前的C++规则很容易把事情搞砸。如果您错误地输入了函数名(或者在其参数列表中犯了错误),那么实际上是(1)而不是(2)。

    您没有错误/警告。在运行时获得惊喜。

        4
  •  2
  •   Jerry Coffin    15 年前

    由于语言不能执行“好”的风格,C++一般甚至不尝试。至少在我看来,在任何情况下,包括这样的冗余说明符是否是一种好的样式(就个人而言,我讨厌它们存在的时候)。

    (至少部分)谷歌的编码标准 可以 在某些情况下是有意义的,但就一般而言,C++通常被认为是平庸的建议。在某种程度上,他们甚至承认——他们中的一些公开声明仅仅是为了符合他们的旧代码。其他部分,他们不直接承认,而且(完全诚实地说)这个论点无论如何也不支持他们的一些标准(例如,其中一些似乎缺乏真正的理由)。

        5
  •  0
  •   Michael Aaron Safyan    15 年前

    这是一个很好的问题,我当然同意,如果在基类中声明了方法virtual,那么重新声明派生类中的方法virtual是一种很好的方式。虽然有一些语言将风格构建成语言(例如谷歌GO,在一定程度上,Python),但是C++不是这些语言中的一种。虽然编译器确实可以检测到派生类不将关键字“virtual”用于基类中声明为“virtual”的内容(或者更重要的是,派生类声明了与基类同名的函数,并且没有在基类中声明为virtual),但实际上,有在发生这种情况时,许多编译器都会发出警告(甚至错误消息)。不过,在这个阶段,在语言中设置这样一个需求是不实际的,因为存在太多不那么严格的代码。此外,开发人员可以选择比语言更严格的语言,并且可以提高编译器的警告级别。