【问题标题】:Is there any point in using `override` when overriding a pure virtual function?覆盖纯虚函数时使用“覆盖”有什么意义吗?
【发布时间】:2018-03-08 20:52:13
【问题描述】:

例如:

class Base {
  virtual void my_function() = 0;
};

class Derived : Base {
  void my_function() override;
};

根据我的阅读,override 关键字用于确保我们在要覆盖的函数中具有正确的签名,而且这似乎是它的唯一用途。

但是,在纯虚函数的情况下,如果我们在派生类(或基类,取决于人们如何看待事物)中使用了不正确的签名,编译器会抛出错误。那么,在Derived::my_function() 声明的末尾添加override 有什么意义吗?

【问题讨论】:

  • 请注意抽象性传播。如果您在Derived 类中提供了错误的签名,那么Derived 类也会变成抽象的。如果没有 override 关键字,可能无法在正确的位置检测到。
  • 它确保如果基类更改与override 断言不兼容,您的代码将无法编译。
  • “有目的地编写教学程序会传播首选的编程实践” - T.J.Elgan
  • 添加它的小好处是一些 IDE 会使用它作为高亮点来显示实现或跳转到父级。

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


【解决方案1】:

是的!!

提高代码清晰度: override 关键字可防止歧义并传达其覆盖其基类方法的含义。

防止可能的意外使用: 将来,如果基类更改方法签名(此处为 virtual),它会强制派生类进行相应更改。 (编译器错误)。否则(没有override关键字)可以认为method overload,这不是故意的。

【讨论】:

  • 虽然隐藏正常,不会是方法重载
【解决方案2】:

通常不打扰override 只是移动一个错误。我找到了更好的出错位置——在你定义无法覆盖的方法时,而不是在实例化类时。

但是,有一种方法可以防止出现运行时错误。

struct Base {
  virtual void foo(int x = 0) = 0;

  void foo(double d) {
      foo( (int)d );
  }
};
inline void Base::foo(int x) { std::cout << "Default foo(" << x << ")\n"; }

struct Derived:Base {
  using Base::foo;
  virtual void foo() { // oops, no int!
    std::cout << "Derived::foo()\n";
    Base::foo();
  }
};
struct Derived2:Derived {
  virtual void foo(int x=0) override {
    std::cout << "Derived2::foo()\n";
    Derived::foo(x);
  }
};

这里我们打算让每个foo 调用其父foo。但是因为Derived::foo 没有覆盖与Base::foo 相同的签名,所以它不会被调用。

在Derived 中的foo() 之后添加override,我们会收到编译时错误。

是的,我实现了纯虚函数Base::foo。

【讨论】:

    【解决方案3】:

    是的,始终使用override 关键字作为防御做法是个好主意。

    当Base 的作者决定my_function 不再是纯虚拟并且它应该采用新参数时,请考虑重新设计。使用override,编译器会发现这个问题;如果没有override,您的Derived 类将继续编译。

    【讨论】:

      【解决方案4】:

      但是,在纯虚函数的情况下,如果我们在派生类中使用了不正确的签名,编译器会抛出错误

      不,这样编译:

      class Base {
        virtual void my_function() = 0;
      };
      
      class Derived : Base {
        void my_function(int);
      //                 ^^^ mistake!
      };
      

      虽然不是这样:

      class Base {
        virtual void my_function() = 0;
      };
      
      class Derived : Base {
        void my_function(int) override;
      };
      

      错误:void Derived::my_function(int) 标记为 override,但不会覆盖


      您所说的错误仅在实例化 Derived - override 时发生,使您可以更早地发现错误并使Derived 的定义更清晰/更具可读性。

      【讨论】:

      • 您可以在另一个类中添加运行时错误,并在实现Base::my_function 的同时使其保持纯虚拟状态。
      • 等等,有什么意义吗?你继续谈论它是如何有用的,但从“不”开始。
      • “否”是对编译器抛出错误的说法的回应。
      • @templatetypedef 这就是重点,当程序员认为他们正在编写的签名应该完全出现在基类中时,他们会覆盖。第一种情况是错误的,因为程序员打算重写函数,但不小心写了一个重载。
      • @templatetypedef 我宁愿不等待构建系统必须按照它的方式工作,尽管编译我的项目的所有其余部分并等到它试图将它们全部链接在一起才能最终拥有它失败。 (或者当您尝试实例化 Derived 时在其他地方失败......)在编译该文件时让它失败会更好,并让它准确指向该行并让它说“这里的这一行是错误的"。
      猜你喜欢
      • 2021-09-30
      • 2013-10-04
      • 2020-08-21
      • 2021-11-01
      • 2014-05-22
      • 2016-02-05
      • 2022-01-13
      • 2020-04-10
      • 1970-01-01
      相关资源
      最近更新 更多