'override'关键字只是检查重写的虚方法吗?

时间:2012-12-14 14:05:54

标签: c++ c++11 inheritance override virtual-method

据我所知,在C ++ 11中引入override关键字只不过是一项检查,以确保正在实现的函数是override virtual基类中的函数。

是吗?

5 个答案:

答案 0 :(得分:223)

这确实是个主意。关键是你明确指出你的意思,以便可以诊断出一个无声的错误:

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

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

上面的代码编译,但不是你的意思(注意缺少的const)。如果你改为virtual int foo() override,那么你会得到一个编译错误,你的函数实际上并没有覆盖任何东西。

答案 1 :(得分:31)

维基百科报价:

  

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

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

编辑(试图改善答案):

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

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

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

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

  3. 添加“覆盖”清楚地消除了歧义:通过这个,人们告诉编译器有三件事需要:

    1. 在超类中有一个名称相同的方法
    2. 超类中的此方法被声明为“虚拟”(意味着,意图重写)
    3. 超类中的方法与子类中的方法(重写方法)具有相同的(输入*)签名
    4. 如果其中任何一个为假,则会发出错误信号。

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

答案 2 :(得分:25)

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

答案 3 :(得分:5)

是的,就是这样。这是一个检查,以确保一个人不会尝试覆盖并通过一个拙劣的签名弄乱它。这是一个维基页面,详细解释了这一点,并有一个简短的说明性示例:

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

答案 4 :(得分:0)

C ++ 17标准草案

遍历C++17 N4659 standard draft上的所有override匹配之后,我可以找到的对override标识符的唯一参考是:

  

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

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
}
     

—结束示例]

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