我有一个带有虚函数的基类,我想在派生类中覆盖该函数。有没有办法让编译器检查我在派生类中声明的函数是否实际覆盖了基类中的函数?我想添加一些宏或某些东西,以确保我不会意外地声明一个新函数,而不是覆盖旧函数。
举个例子:
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 ++)?你如何避免这些问题?
答案 0 :(得分: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;
};
答案 1 :(得分:20)
C#的override
关键字不属于C ++。
在gcc中,-Woverloaded-virtual
警告不要使用同名函数隐藏基类虚函数,但签名应该不会覆盖它。但是,它不会保护您免于因错误拼写函数名本身而无法覆盖函数。
答案 2 :(得分:17)
据我所知,你不能把它抽象化吗?
class parent {
public:
virtual void handle_event(int something) const = 0 {
// boring default code
}
};
我以为我在www.parashift.com上看到你实际上可以实现一个抽象方法。这对我个人来说是有意义的,它唯一能做的就是强制子类来实现它,没有人说它不允许有自己的实现。
答案 3 :(得分:11)
在MSVC中,即使您没有为CLR编译,也可以使用CLR override
关键字。
在g ++中,在所有情况下都没有直接的强制执行方式;其他人就如何使用-Woverloaded-virtual
捕获签名差异给出了很好的答案。在将来的版本中,有人可能会使用C ++ 0x语法添加__attribute__ ((override))
等语法或等效语法。
答案 4 :(得分:9)
在MSVC ++中,您可以使用keyword override
class child : public parent { public: virtual void handle_event(int something) override { // new exciting code } };
override
适用于MSVC ++中的本机代码和CLR代码。
答案 5 :(得分: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. */ }
答案 6 :(得分:3)
我建议你的逻辑略有改变。根据您需要完成的任务,它可能会也可能不会起作用。
handle_event()仍然可以执行“无聊的默认代码”,但不是虚拟的,在你想要它做的地方,“新的激动人心的代码”让基类调用一个抽象的方法(即必须 - 被子类提供的重写方法。
编辑:如果你以后决定你的一些后代类不需要提供“新的令人兴奋的代码”,那么你可以将抽象更改为虚拟并提供一个空的基类实现“插入”功能。
答案 7 :(得分:2)
如果基类函数被隐藏,您的编译器可能会发出警告。如果是,请启用它。这将捕获参数列表中的const冲突和差异。不幸的是,这不会发现拼写错误。
例如,这是在Microsoft Visual C ++中警告C4263。
答案 8 :(得分:1)
C ++ 11 override
关键字与派生类内部的函数声明一起使用时,会强制编译器检查声明的函数是否实际上重写了某些基类函数。否则,编译器将引发错误。
因此,您可以使用override
说明符来确保动态多态(函数覆盖)。
class derived: public base{
public:
virtual void func_name(int var_name) override {
// statement
}
};
答案 9 :(得分:0)
class MyClass {
public:
MyClass() {}
virtual uint32_t someFunction(bool param = false) {
if (param) {
std::cout << "This is an example virtual function with default code" << std::endl;
}
return 1100; //just for return something
};
class MyClass2 : public MyClass {
public:
MyClass2();
uint32_t someFunction(bool param) override;
};
uint32_t MyClass2::someFunction(bool verbose) {
std::cout << "This is new implementation for virtual method " << std::endl;
}