是否建议明确地使覆盖函数成为虚拟的?

时间:2013-09-12 13:15:07

标签: c++ c++11 override virtual

在C ++ 11之前,当在派生类中重写虚函数时,建议将virtual关键字也添加到派生类函数中以使意图清晰。

现在这样的功能被标记为“覆盖”,其中包括必须存在虚拟基本功能的概念。因此我现在更喜欢省略虚拟:

class Derived: public Base {
public:
  void Overriden() override;
  // Instead of: virtual void Overriden() override;
};

然而,这会导致MSVC 2012中的IntelliSense错误: 'override'修饰符需要一个带有显式'virtual'关键字的虚函数声明

显然编译器会编译类,但错误让我想到了它。是否仍有正当理由添加虚拟关键字?

3 个答案:

答案 0 :(得分:3)

documentationoverride关键字报告的

,其含义是手头的函数必须覆盖虚函数:

  

在方法声明中,override指定该函数必须是   覆盖基类方法。

这是强制执行(即使编译器强制执行)此类要求的手段。当然,如果基类的函数不是虚函数,代码将无法编译。因此,正如您所指出的,添加虚拟是多余的。

我认为在c ++ 11之前添加它并不是一个好建议。请考虑以下代码段:

#include <iostream>

using namespace std;

class A{
    public:
    void f(){
        cout << "A" << endl;
    }
};

class B : public A{
    public:
    virtual void f(){
        cout << "B" << endl;
    };
};

class C : public B{
    public:
    void f(){
        cout << "C" << endl;
    };
};

int main( int argc, char* argv[] ) 
{
    C c;
    A& aref = c;
    aref.f();
    B& bref = c;
    bref.f();
}

其输出显然是“A”,后跟“C”。如您所见,在virtual中添加class C根本不会产生任何影响,而virtual中的class B则起着关键作用。遵循将virtual添加到class C的约定会让人更难以一目了然。

答案 1 :(得分:1)

我认为这更像是品味问题: - )

我更喜欢只在定义后面写覆盖,这意味着该函数已经是虚拟的。程序员根据定义是懒惰的,所以保持简短的源: - )

我们在编码指南中添加了一条规则,其中覆盖是必须的,虚拟应该在正常更改过程中或在重构实际类时从旧代码中删除。

但这只是我们的解决方案,而且没有技术原因!

答案 2 :(得分:0)

是的,在覆盖基类行为时,您应该更喜欢使用virtual而不是#include <iostream> using namespace std; class Base { public: virtual void foo() { std::cout << "BASE foo" << std::endl; } void bar() { std::cout << "BASE bar" << std::endl; } }; class A : public Base{ public: void foo() override { std::cout << "A foo" << std::endl; } virtual void bar() { std::cout << "A bar" << std::endl; } }; class B : public A { public: void bar() override { std::cout << "B bar" << std::endl; } }; int main(int argc, char *argv[]) { B b; A *a = &b; Base *base = &b; base->foo(); a->foo(); base->bar(); a->bar(); return 0; } 。因为它可能导致可能的错误

这怎么可能导致错误? 这是一个例子,

A foo
A foo
BASE bar
B bar

输出将是

foo()

bar被正确覆盖,但bar()未被覆盖,并且在某些情况下会被隐藏。即使基础对象是相同的

,对override的调用也不会调用相同的方法

如果我们强制要求在覆盖时始终使用virtual而在void bar() override {}仅定义新的虚拟函数,那么当我们尝试error: ‘void A::bar()’ marked ‘override’, but does not override时,编译器会抱怨{{1}}

这正是Autosar specification定义以下规则

的原因
  

规则A10-3-1(必需,实施,自动化)   虚函数声明应包含三个说明符中的一个:(1)虚拟,(2)覆盖,(3)最终。

     

理由:   指定这三个说明符中的多个以及虚函数声明是多余的,并且是潜在的错误来源。