“ override”关键字是否只是对覆盖的虚拟方法的检查?


226

据我了解,overrideC ++ 11 中关键字的引入无非是一项检查,以确保所实现overridevirtual函数是基类中函数的作用。

是吗


50
Yes.⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣
R.费尔南德斯Martinho

13
不过,这不是双重检查。这是唯一的支票。
Nikos C.

13
嘿,override不是关键字,它是一种语法糖。int Override = 42; // OK
KAlO2 2014年

2
解释声明的函数被覆盖,它还提高了可读性;)
mots_g 2014年

5
所以,呃...什么时候C ++ 11会变得足够标准,以至于他们在我当地的四年制课程中开始教授类似的东西?他们什么时候知道?
Cinch

Answers:


263

确实是这个主意。关键是您要清楚自己的意思,以便可以诊断出其他无提示的错误:

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

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

上面的代码可以编译,但不是您想要的(请注意缺少的内容const)。如果改为,virtual int foo() override则将出现编译器错误,即您的函数实际上并未覆盖任何内容。


74
+1:不过,不幸的是,当人们建议新override功能“修复”此问题时,这有点让人头疼。您必须记住要使用它,就像您应该记得写过const;)
轨道上的竞速赛

我只是意识到explicit类定义没有进入C ++ 11。嗯
aschepler

1
@aschepler那么explicit类定义会做什么?从来没有听说过。
Christian Rau

18
@LightnessRacesinOrbit:是的,这不是傻瓜。然而,回忆(疯狂地写作的一般规律override,当一个打算这样做)是更有可能比记忆角落的情况下,即没有在复制不同的原型的功能,只有违规像缺少一般性const或写char,而不是int
legends2k

1
@Light,override此答案中提到了指定符的最佳用例,这比直接使用更具未来性。答案表明,overridevirtual方法保持一致。将来,如果一个人错误地更改了签名,它的作用
就会发挥作用。– iammilind

35

维基百科报价:

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

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

编辑(尝试改善答案):

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

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

  1. 一个人在新方法中输入了错误的类型。编译器不知道要编写先前的方法,只是将其作为新方法添加到类中。问题在于旧方法仍然存在,新方法只是作为重载而添加。在这种情况下,对旧方法的所有调用将像以前一样起作用,而行为没有任何变化(这正是重写的目的)。

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

添加“ override”显然消除了歧义:通过这一点,一个告诉编译器期望的是三件事:

  1. 在超类中有一个同名的方法
  2. 超类中的此方法被声明为“虚拟”(意味着,将被重写)
  3. 超类中的方法具有与子类中的方法(重写方法)相同的(input *)签名

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

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


31

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


1
+1。虽然虽然override是发现此类问题的好方法,但良好的单元测试范围也应有所帮助。
幻灭了

1
这就是为什么我对这个新说明符感到如此兴奋的原因。唯一的问题是必须已应用此功能,以防止由于基类的更改而导致的错误。;-)
Wolf


2

C ++ 17标准草案

经过所有的 override仔细研究了C ++ 17 N4659标准草案中的所有内容之后,我可以找到的对该override标识符的唯一参考是:

5如果虚拟函数被virt-specifier覆盖标记,并且不覆盖基类的成员函数,则程序格式错误。[示例:

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
}

—结束示例]

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.