首页 > 代码库 > 条款37: 决不要重新定义继承而来的非虚函数

条款37: 决不要重新定义继承而来的非虚函数

class B {public:  void mf();  ...};class D: public B { ... };

甚至对B,D或mf一无所知,也可以定义一个类型D的对象x,

D x;                          // x是类型D的一个对象

那么,如果发现这么做:

B *pB = &x;                   // 得到x的指针

pB->mf();                     // 通过指针调用mf

和下面这么做的执行行为不一样:

D *pD = &x;                   // 得到x的指针

pD->mf();                     // 通过指针调用mf

你一定就会感到很惊奇。

如果mf是非虚函数而D又定义了自己的mf版本,行为就不会相同:

class D: public B {public:  void mf();                  // 隐藏了B::mf; 参见条款50  ...};pB->mf();                     // 调用B::mfpD->mf();                     // 调用D::mf

名字查找与继承:(函数调用步骤)

假设调用p->mem()

1.首先确定p的静态类型

2.在p的静态类型对应的类中查找,如果找不到,则依次在直接基类中不断查找直至到达继承链的顶端,如果找遍了该类及其基类仍然找不到,编译器将报错

3.一旦找到mem,就进行常规的类型检查,以确认对于当前找到的mem,本次调用是否合法

4.假设调用合法,则编译器根据调用的是否是虚函数而产生不同的代码:

如果mem是虚函数且我们是通过引用或指针进行的调用,则编译器产生的代码将在运行时确定到底运行该虚函数的哪个版本,依据是对象的动态类型;

反之,则编译器将产生一个常规函数调用,即静态绑定