一、看一个隐藏non-virtual函数的例子
- 假设class D以public的方式继承于class B,代码如下:
class B {
public:
void mf();
};
class D :public B {};
int main()
{
D x;
B *pB = &x;
pB->mf(); //调用B::mf()
D *pD = &x;
pD->mf(); //调用D::mf()
return 0;
}
二、静态绑定与动态绑定
- 关于静态绑定、动态绑定可以参阅文本的一些其余文章:
静态绑定
- 当我们调用non-virtual函数时,调用的函数版本与指针的类型有关
- 例如,上面的pB指针在初始化时,将与D对象中的B对象所绑定;上面的pD指针在初始化时,将与D对象所绑定。这是静态绑定
- 因此,pB调用的是B::mf();pD调用的是D::mf()
动态绑定
- 当我们调用virtual函数时,调用的函数版本与指针所指的对象有关
- 对virtual函数的调用,是在代码运行期间执行的。例如,如果上面的D::mf()是一个虚函数,那么会有:
class B { public: virtual void mf(); }; class D :public B { public: virtual void mf(); }; int main() { D x; B *pB = &x; pB->mf(); //调用D::mf() D *pD = &x; pD->mf(); //调用D::mf() return 0; }
三、为什么不建议派生类隐藏基类的non-virtual函数
- 在条款32介绍过,public继承意味着is-a关系,条款34描述了为什么在class内声明一个non-virtual函数会为该class建立起一个不变性,凌驾其特异性。如果:
- 我们在派生类中隐藏了基类的non-virtual函数,那么基类与派生类就会产生行为上的不一致,is-a关系就消失了
- 如果想要表现出派生类与基类的不同,那么应该将函数声明为virtual(其中虚析构函数是一个例子)
四、总结
- 绝对不要重新定义继承而来的non-virtual函数