安全地覆盖 C + + 虚函数

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

举个例子:

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

114265 次浏览

I would suggest a slight change in your logic. It may or may not work, depending on what you need to accomplish.

handle_event() can still do the "boring default code" but instead of being virtual, at the point where you want it to do the "new exciting code" have the base class call an abstract method (i.e. must-be-overridden) method that will be supplied by your descendant class.

EDIT: And if you later decide that some of your descendant classes do not need to provide "new exciting code" then you can change the abstract to virtual and supply an empty base class implementation of that "inserted" functionality.

Your compiler may have a warning that it can generate if a base class function becomes hidden. If it does, enable it. That will catch const clashes and differences in parameter lists. Unfortunately this won't uncover a spelling error.

For example, this is warning C4263 in Microsoft Visual C++.

Something like C#'s override keyword is not part of C++.

In gcc, -Woverloaded-virtual warns against hiding a base class virtual function with a function of the same name but a sufficiently different signature that it doesn't override it. It won't, though, protect you against failing to override a function due to mis-spelling the function name itself.

As far as I know, can't you just make it abstract?

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

I thought I read on www.parashift.com that you can actually implement an abstract method. Which makes sense to me personally, the only thing it does is force subclasses to implement it, no one said anything about it not being allowed to have an implementation itself.

In MSVC, you can use the CLR override keyword even if you're not compiling for CLR.

In g++, there's no direct way of enforcing that in all cases; other people have given good answers on how to catch signature differences using -Woverloaded-virtual. In a future version, someone might add syntax like __attribute__ ((override)) or the equivalent using the C++0x syntax.

Make the function abstract, so that derived classes have no other choice than to override it.

@Ray Your code is invalid.

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

Abstract functions cannot have bodies defined inline. It must be modified to become

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


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

In MSVC++ you can use keyword override

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

override works both for native and CLR code in MSVC++.

Since g++ 4.7 it does understand the new C++11 override keyword:

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;
};

C++11 override keyword when used with the function declaration inside the derived class, it forces the compiler to check that the declared function is actually overriding some base class function. Otherwise, the compiler will throw an error.

Hence you can use override specifier to ensure dynamic polymorphism (function overriding).

class derived: public base{
public:
virtual void func_name(int var_name) override {
// statement
}
};
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
};


 

  • then you can override the function as you need
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;


}