253

据我了解,override在 C++11 中引入关键字无非是检查以确保正在实现的函数是基类中函数的overrideing 。virtual

是这样吗?

4

6 回答 6

288

确实是这样的想法。关键是您要明确说明您的意思,以便可以诊断出其他无声的错误:

struct Base
{
    virtual int foo() const;
};

struct Derived : Base
{
    virtual int foo()   // whoops!
    {
       // ...
    }
};

上面的代码可以编译,但不是您的意思(注意缺少的const)。如果您改为使用virtual int foo() override,那么您将收到编译器错误,表明您的函数实际上并未覆盖任何内容。

于 2012-12-14T14:13:28.807 回答
39

维基百科引用:

覆盖特殊标识符意味着编译器将检查基类以查看是否存在具有此确切签名的虚函数。如果没有,编译器会出错。

http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final

编辑(试图改进一点答案):

将方法声明为“覆盖”意味着该方法旨在重写基类上的(虚拟)方法。重写方法必须与它打算重写的方法具有相同的签名(至少对于输入参数)。

为什么这是必要的?好吧,防止了以下两种常见的错误情况:

  1. 一个人在新方法中打错了一个类型。编译器不知道它打算编写以前的方法,只是将其作为新方法添加到类中。问题是旧方法仍然存在,新方法只是作为重载添加。在这种情况下,对旧方法的所有调用都将像以前一样运行,而不会改变行为(这本来就是重写的目的)。

  2. 忘记将超类中的方法声明为“虚拟”,但仍试图在子类中重写它。虽然这显然会被接受,但行为不会完全符合预期:该方法不是虚拟的,因此通过指向超类的指针访问将结束调用旧的(超类')方法而不是新的(子类')方法。

添加“覆盖”清楚地消除了这一点:通过这个,一个人告诉编译器期待三件事:

  1. 超类中有同名方法
  2. 超类中的这个方法被声明为“虚拟”(这意味着,打算被重写)
  3. 超类中的方法与子类中的方法(重写方法)具有相同的(输入*)签名

如果其中任何一个为假,则发出错误信号。

* 注意:输出参数有时是不同的,但相关的类型。如果有兴趣,请阅读协变和逆变转换。

于 2012-12-14T14:09:08.637 回答
36

当有人更新基类虚拟方法签名(例如添加可选参数)但忘记更新派生类方法签名时,发现“覆盖”很有用。在这种情况下,基类和派生类之间的方法不再是多态关系。如果没有覆盖声明,很难找出这种错误。

于 2015-03-26T22:50:36.170 回答
5

是的,就是这样。这是一项检查,以确保不会尝试覆盖并通过拙劣的签名将其搞砸。这是一个 Wiki 页面,详细解释了这一点,并有一个简短的说明性示例:

http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final

于 2012-12-14T14:08:46.450 回答
4

C++17 标准草案

在浏览了C++17 N4659 标准草案的所有override命中后,我能找到的唯一参考标识符是:override

5 如果一个虚函数被 virt-specifier override 标记并且没有覆盖一个基类的成员函数,那么这个程序是非良构的。[ 例子:

struct B {
  virtual void f(int);
};

struct D : B {
  virtual void f(long) override; // error: wrong signature overriding B::f
  virtual void f(int) override;  // OK
}

—结束示例]

所以我认为可能炸毁错误的程序实际上是唯一的效果。

于 2019-02-05T13:42:33.283 回答
0

澄清关于虚拟的一切(因为我一直在反复遇到这个问题!)。

  • virtual是为了基类告诉派生类一个函数可以被覆盖
    • 没有必要virtual在派生类中使用。如果一个函数具有相同的名称/参数类型 list/cv-qual/ref-qual,它将自动正确使用。
    • (实际上,virtual在派生类中使用会产生细微的错误,见下文)
  • override派生类捕获错误和文档代码 的可选说明符
    • 告诉编译器:“确保有一个我正在重写的 EXACT 虚函数”
      • 避免错误地创建一个不同的函数签名,这会导致一个微妙的错误(即两个稍微不同的函数,它们是相同的)
      • 告诉编码人员这是覆盖虚函数

所以给出:

class base
{
public:
    virtual int foo(float x);
};

这里将如何处理一些不同的覆盖:

// AUTOMATIC virtual function (matches original, no keywords specified)
int foo(float x) { ; } 

// Re-specifying "virtual" uselessly (+ see pitfalls below)
virtual int foo(float x) { ; } 

// Potential issues: it is unknown if the author intended this to be a 
//    virtual function or not. Also, if the author DID intend a match but 
//    made a mistake (e.g. use "int" for the parameter), this will create
//    a subtle bug where the wrong function is called with no warning anywhere:

int foo(int x) { ; }         // SUBTLE, SILENT BUG! int instead of float param
virtual int foo(int x) { ; } // SUBTLE, SILENT BUG! int instead of float param


// Better approach: use the 'override' identifier to 
//    make sure the signature matches the original virtual function,
//    and documents programmer intent.

int foo(float x) override { ; }        // Compiler checks OK + tells coder this is virtual
int foo(int x)  override { ; }         // COMPILE ERROR, caught subtle bug
virtual int foo(int x)  override { ; } // COMPILE ERROR, caught subtle bug
                                       // (and redundant use of "virtual")

最后(!),final可以使用说明符代替,override原因相同,但如果您不希望在派生类中进一步覆盖

于 2021-10-18T14:36:32.220 回答