Item 12: Declare overriding functions override.

Item 12: Declare overriding functions override.

Effective Modern C++ Item 12 的学习和解读。

面向对象的 C++ 主要特性是类、继承、虚函数,而这些特性的基础是继承类中重写基类的虚函数。重写(overriding)和重载(overloading)看着比较相似,但其实完全不同。重写的一个例子:

class Base {
public:virtual void doWork(); // base class virtual function...
};class Derived: public Base {
public:virtual void doWork();  // overrides Base::doWork ("virtual" is optional here)...
};std::unique_ptr<Base> upb = std::make_unique<Derived>();
...
upb->doWork(); // call doWork through base class ptr; derived class function is invoked

重写需要满足的条件:

  • 基类的重写函数必须是虚函数。
  • 基类和继承类的重写函数的函数名必须相同。
  • 基类和继承类的重写函数的参数类型必须相同。
  • 基类和继承类的重写函数的常量属性必须相同。
  • 基类和继承类的重写的函数的返回值类型和异常规格说明要兼容。

除了 C++98 的这些限制条件,C++11 还增加了一条:

  • 基类和继承类的重写函数的引用修饰符必须相同。

引用修饰符包括左值和右值两种,左值引用成员函数可以被 *this 为左值调用,右值引用成员函数可以被 *this 为右值调用。看一个例子:

#include class Widget {
public:void doWork() & {   // this version of doWork applies only when *this is an lvaluestd::cout << "doWork() &" << std::endl;}void doWork() && {  // this version of doWork applies only when *this is an rvaluestd::cout << "doWork() &&" << std::endl;}
};Widget makeWidget()  { // factory function (returns rvalue)return Widget();
}int main() {Widget w;w.doWork();makeWidget().doWork();
}// 打印信息
doWork() &
doWork() &&

这里,w 是个左值,所以调用的是 doWork() & 函数,而 makeWidget() 返回的是一个右值,所以调用的是 doWork() && 函数。

重写的条件是非常严格的,细小的差错将会导致完全不同的结果。看个例子:

class Base {
public:virtual void mf1() const;virtual void mf2(int x);virtual void mf3() &;void mf4() const;
};class Derived: public Base {
public:virtual void mf1();  // 缺少 constvirtual void mf2(unsigned int x); // 参数类型不同virtual void mf3() &&;  // 引用修饰符不同void mf4() const;  // 基类没有加 virtual 修饰
};

以上代码,有的编译器会给出警告,有的编译器给的警告不全,还有的编译器不会给警告。所以保险的做法是自己将重写函数标记为 override,这样的话,不符合重写条件的话,编译器一定会报错。

所以,当你在继承类中要重写函数的话,加上 override 吧!


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部