首页 文章

安全地覆盖C虚函数

提问于
浏览
94

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

举个例子:

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)?你如何避免这些问题?

8 回答

  • 9

    从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 警告不要使用相同名称的功能隐藏基类虚函数,但是它没有完全不同的签名,但是,保护您不会因为错误拼写函数名本身而无法覆盖函数 .

  • 81

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

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

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

  • 16

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

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

  • 11

    在MSVC中你可以使用keyword override

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

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

  • 3

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

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

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

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

    编辑:如果你以后决定你的一些后代类不需要提供"new exciting code"那么你可以将抽象更改为虚拟并提供该"inserted"功能的空基类实现 .

  • 2

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

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

相关问题