安全地覆盖C ++虚函数

问题描述 投票:96回答:8

我有一个带有虚函数的基类,我想在派生类中重写该函数。有没有办法让编译器检查我在派生类中声明的函数是否实际覆盖了基类中的函数?我想添加一些宏或某些东西,以确保我不会意外地声明一个新的功能,而不是覆盖旧的功能。

举个例子:

class parent {
public:
  virtual void handle_event(int something) const {
    // boring default code
  }
};

class child : public parent {
public:
  virtual void handle_event(int something) {
    // new exciting code
  }
};

int main() {
  parent *p = new child();
  p->handle_event(1);
}

这里调用parent::handle_event()而不是child::handle_event(),因为孩子的方法错过了const声明,因此声明了一种新方法。这也可能是函数名中的拼写错误或参数类型中的一些细微差别。如果基类的接口发生更改,某些派生类未更新以反映更改,则也很容易发生。

有没有办法避免这个问题,我能以某种方式告诉编译器或其他工具为我检查这个吗?任何有用的编译器标志(最好是g ++)?你如何避免这些问题?

c++ override virtual-functions
8个回答
84
投票

从g ++ 4.7开始,它确实理解了新的C ++ 11 override关键字:

class child : public parent {
    public:
      // force handle_event to override a existing function in parent
      // error out if the function with the correct signature does not exist
      void handle_event(int something) override;
};

20
投票

像C#的override关键字这样的东西不是C ++的一部分。

在gcc中,-Woverloaded-virtual警告不要使用相同名称的函数隐藏基类虚函数,但是它不会覆盖它。但是,它不会保护您免于因错误拼写函数名称本身而无法覆盖函数。


17
投票

据我所知,你不能把它抽象化吗?

class parent {
public:
  virtual void handle_event(int something) const = 0 {
    // boring default code
  }
};

我以为我在www.parashift.com上看到你实际上可以实现一个抽象方法。这对我个人来说是有意义的,它唯一能做的就是强制子类来实现它,没有人说它不允许有自己的实现。


11
投票

在MSVC中,即使您没有编译CLR,也可以使用CLR override关键字。

在g ++中,没有直接的方法可以在所有情况下执行;其他人就如何使用-Woverloaded-virtual捕捉签名差异给出了很好的答案。在未来的版本中,有人可能会使用C ++ 0x语法添加类似__attribute__ ((override))或等效语法的语法。


9
投票

在MSVC ++中,您可以使用keyword override

    class child : public parent {
    public:
      virtual void handle_event(int something) override {
        // new exciting code
      }
    };

override适用于MSVC ++中的本机代码和CLR代码。


5
投票

使函数成为抽象,以便派生类除了覆盖它之外别无选择。

@Ray您的代码无效。

class parent {
public:
  virtual void handle_event(int something) const = 0 {
    // boring default code
  }
};

抽象函数不能具有内联定义的实体。它必须修改成为

class parent {
public:
  virtual void handle_event(int something) const = 0;
};

void parent::handle_event( int something ) { /* do w/e you want here. */ }

3
投票

我建议你的逻辑略有改变。根据您需要完成的任务,它可能会也可能不会起作用。

handle_event()仍然可以执行“无聊的默认代码”,但不是虚拟的,而是在你想要它做的地方“新的令人兴奋的代码”让基类调用一个抽象方法(即必须被覆盖)的方法这将由你的后代班级提供。

编辑:如果你以后决定你的一些后代类不需要提供“新的令人兴奋的代码”,那么你可以将抽象更改为虚拟并提供该“插入”功能的空基类实现。


2
投票

如果基类函数被隐藏,您的编译器可能会发出警告。如果是,请启用它。这将捕获参数列表中的const冲突和差异。不幸的是,这不会发现拼写错误。

例如,这是Microsoft Visual C ++中的C4263警告。

© www.soinside.com 2019 - 2024. All rights reserved.