8

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

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

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

但是,这会导致 MSVC 2012 中的 IntelliSense 错误:“覆盖”修饰符需要带有显式“虚拟”关键字的虚函数声明

显然编译器编译了类,但是错误让我思考。添加 virtual 关键字还有正当理由吗?

4

3 回答 3

4

如关键字文档中所述override,其含义是手头的函数必须覆盖虚函数:

在方法声明中,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”。如您所见,添加根本不会产生任何影响,而virtualin起着关键作用。遵守添加to的惯例会使这一点更难一目了然。class Cvirtualclass Bvirtualclass C

于 2013-09-12T13:26:12.827 回答
1

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

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

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

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

于 2013-09-12T13:28:11.657 回答
0

是的,您应该更喜欢在覆盖基类行为时使用override而不是。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

这正是Autosar 规范定义以下规则的原因

规则 A10-3-1(必需、实现、自动) 虚函数声明应包含以下三个说明符之一:(1) virtual,(2) override,(3) final。

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

于 2018-04-02T23:47:36.060 回答