【问题标题】:Is it recommended to explicitly make overriding functions virtual?是否建议显式将覆盖函数设为虚拟?
【发布时间】:2013-09-16 21:44:06
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 只是风格上的。如果该函数可以被覆盖,我会使用virtual。 (如果是final,我不会。)这对读者来说似乎更直观。
  • 我赞成 Stefano Falasca 的解释,但接受 Klaus 的回答,因为它似乎更适合这个问题。
  • virtual 表示“可以被覆盖”,而不是“这是一个覆盖”。

标签: c++ c++11 overriding virtual


【解决方案1】:

正如documentation 中针对override 关键字所报告的,其含义是手头的函数必须覆盖一个虚函数:

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

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

我认为在 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”。如您所见,在class C 中添加virtual 完全没有效果,而在class B 中的virtual 起着关键作用。遵守将virtual 添加到class C 的惯例会让人难以一目了然。

【讨论】:

  • @MatthieuM。确实如此。事实上,我添加了一个主要的,显示它。希望对您有所帮助。
  • 啊,抱歉,没有看到A 没有virtual。抱歉打扰了。
【解决方案2】:

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

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

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

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

【讨论】:

    【解决方案3】:

    是的,在覆盖基类行为时,您应该更喜欢使用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 specification 定义以下规则的原因

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-26
      • 2021-11-01
      • 1970-01-01
      • 2016-02-05
      • 2016-12-16
      • 2022-01-13
      • 2013-10-04
      • 2011-03-15
      相关资源
      最近更新 更多