Effective C++——条款36(第6章)
来源:互联网 发布:北京java培训学校 编辑:程序博客网 时间:2024/06/06 03:22
条款36: 绝不重新定义继承而来的non-virtual 函数
Never redefine an inherited non-virtual function假设 class D系由 class B以 public 形式派生出来,class B定义有一个 public 成员函数mf.由于mf的参数和返回值都不重要,所以假设两者皆为 void .
class B {public: void mf();};class B : public B { ... };虽然对B,D和mf一无所知,但面对一个类型为D的对象 x:
D x; // x是一个类型为D的对象如果以下行为:
B *pB = &x; // 获得一个指针指向xpB->mf(); // 经由该指针调用mf异于以下行为:
D *pD = &x;pD->mf();两者都通过对象 x 调用成员函数 mf,由于两者所调用的函数都相同,所以行为应该相同,是吗?
是的,一般如此.更明确地说,如果mf是个non-virtual 函数而D定义有自己的mf,那就不是如此:
class D : public B {public: void mf(); // 遮掩了B::mf ...};pB->mf(); // 调用B::mfpD->mf(); // 调用D::mf造成此一两面行为的原因是,non-virtual 函数如B::mf和D::mf都是静态绑定(staticlly bound,详见条款37).这意思是说,由于pB被声明为一个pointer-to-B,通过pB调用的non-virtual 函数永远是B所定义的版本,即使pB指向一个类型为"D派生的class"的对象.
但另一方面,virtual 函数却是动态绑定(dynamically bound,详见条款37),所以它们不受这个问题困扰.如果mf是个 virtual 函数,不论是通过pB或pD调用mf,都会导致调用D::mf,因为pB和pD真正指的都是一个类型为D的对象.
如果正在编写 class D并重新定义继承自 class B的non-virtual 函数mf,D对象很可能展现出不一致的行为.更明确地说,当mf被调用,任何一个D对象都可能展现出B或D的行为:决定因素不在对象自身,而在于"指向该对象的指针"当初的声明类型.
但那只是实务面上的讨论,真正的理论层面的理由,接下来讨论.
条款32已经说过,所谓 public 继承意味is-a的关系.条款34则描述为什么在 class 内声明一个non-virtual 函数会为该 class 建立起一个不变性,凌驾其特异性.如果将这两个观点施行于两个 class B和D以及non-virtual 成员函数B::mf身上,那么:
适用于B对象的每一件事,也适用于D对象,因为每个D对象都是一个B对象.
B的derived class 一定会继承mf的接口和实现,因为mf是B的一个non-virtual 函数.
现在,如果D重新定义mf,设计便出现矛盾.既然D以 public 形式继承B,并且mf是B的一个non-virtual 函数,那么D的mf行为和B的mf行为必须是一致的.但D又重新定义mf,这就发生了矛盾.
因此,任何情况下都不应该重新定义一个继承而来的non-virtual 函数.
同时这个条款也解释了为什么多态性base class 内的析构函数应该是 virtual.如果违反了这个准则,在base class 内声明一个non-virtual 析构函数,那么在derived class 就不能重新定义一个派生类的non-virtual 析构函数.但即使没有重新定义non-virtual 析构函数,编译器也会为derived class 定义一个默认的析构函数,仍然发生矛盾.
注意:
绝对不要重新定义继承而来的non-virtual 函数.
0 0
- Effective C++——条款36(第6章)
- Effective C++——条款6(第2章)
- Effective C++——条款32(第6章)
- Effective C++——条款33(第6章)
- Effective C++——条款34(第6章)
- Effective C++——条款35(第6章)
- Effective C++——条款37(第6章)
- Effective C++——条款38(第6章)
- Effective C++——条款39(第6章)
- Effective C++——条款40(第6章)
- Effective C++——条款10条,条款11和条款12(第2章)
- Effective C++——条款3(第1章)
- Effective C++——条款4(第1章)
- Effective C++——条款5(第2章)
- Effective C++——条款7(第2章)
- Effective C++——条款8(第2章)
- Effective C++——条款9(第2章)
- Effective C++——条款13(第3章)
- Invalidate()和UpdateWindow()的区别
- eclipse中配置tomcat的路径问题
- iOS开发中常用的设计模式
- IOS开发—IOS绘制圆,直线,弧线,矩形,扇形,三角形,贝塞尔等图形
- Javascript高级程序设计第十四章(表单)
- Effective C++——条款36(第6章)
- ssh实现clob存储大文本数据
- Untiy3D笔记之番外篇——判断手指滑动方向之角度篇
- 面向对象思想
- jQuery-动画
- 2053 Switch Game
- 闪存数据库概念与技术
- Struts2自定义类型转换器分为局部类型转换器和全局类型转换器
- APP的启动速度测试