安全地覆盖C ++虚函数

我有一个虚拟函数的基类,我想在派生类中重写该函数。 有没有办法让编译器检查,如果我在派生类中声明的函数实际上覆盖了基类中的函数? 我想添加一些macros或确保我没有意外地声明一个新的函数,而不是重写旧的。

以这个例子:

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声明,因此声明了一个新的方法。 这也可能是函数名称中的拼写错误或参数types中的一些细微差别。 如果基类的接口发生变化,并且某些派生类没有更新以反映变化,也很容易发生。

有没有办法避免这个问题,我可以不知何故告诉编译器或其他工具来检查这个对我? 任何有用的编译器标志(最好用于g ++)? 你如何避免这些问题?

由于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 virtual void handle_event(int something) override; }; 

像C#的override关键字不是C ++的一部分。

在gcc中, -Woverloaded-virtual用一个同名的函数来隐藏一个基类虚函数,但是这个函数的签名是完全不同的,它不会覆盖它。 但是,它不会保护您不会因为错误地将函数名称本身错误而覆盖函数。

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

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

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

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

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

在MSVC ++中,您可以使用关键字override

    上class的孩子:公开的父母{
    上市:
       virtual void handle_event(int something) override {
         //新的令人兴奋的代码
       }
     };

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

使函数抽象,以便派生类没有其他select,而不是重写它。

@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. */ } 

我会build议你的逻辑略有改变。 它可能会或可能不会工作,这取决于你需要完成什么。

handle_event()仍然可以做“无聊的默认代码”,但不是虚拟的,在你希望它做的“新兴奋的代码”的基点类调用一个抽象方法(即必须重写)的方法这将由你的后代课程提供。

编辑:如果你后来决定,你的一些后代类不需要提供“新的激动人心的代码”,那么你可以改变抽象为虚拟和提供一个空的基类实现的“插入”function。

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

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