Effective C++读书笔记(十一)继承与面向对象设计部分(下)
2018-03-15 11:19
218 查看
读书笔记中涉及到的所有代码实例可通过https://github.com/LuanZheng/EffectiveCPlusPlus.git进行下载获得。
Item36 绝不重新定义继承来的non-virtual函数
non-virtual函数都是静态绑定的。这意思是说,由于pB被声明为一个point-to-B,通过pB调用的non-virtual函数永远是B所定义的版本,即使pB指向一个类型为”B派生之class”的对象。
但另一方面,虚函数确实动态绑定的。所以它们不受这个问题之苦。
任何情况下都不应该重新定义一个继承而来的non-virtual函数。
例子见Item36
Item37 绝不重新定义继承而来的缺省参数值
virtual函数系动态绑定,而缺省参数值却是静态绑定。
对象的所谓静态类型,就是它在程序中被声明时所采用的类型。对象的所谓动态类型,则是指目前所指对象的类型。
因此,若重新定义继承而来的缺省参数值(virtual函数),则会发生错乱。若用基类指针指向派生类,则在调用函数时,会发生函数执行的是派生类的方法,却使用的是基类的默认参数。
若将派生类的参数定义为和基类一样,不但代码重复,且代码带着相依性。
当virtual函数需要默认参数时,最好的方法是使用NVI手法。另non-virtual函数调用virtual函数。将默认参数提取到non-virtual函数中。virtual函数不需要定义默认参数。
可以看到,同样的Circle对象的draw方法,产生的结果不一样。一次为绿色,一次为红色。这增加了混乱程度。需要利用NVI方式整改,整改的结果可参考例子。
例子见Item37
Item38 通过复合塑模出has-a或“根据某物实现出”
复合的意义和public继承完全不同.
在应用域,复合意味着has-a,在实现域,复合意味着is-implemented-in-terms-of.
Item35中的stragegy策略就体现着复合的设计.
Item39 明智而审慎的使用private继承
如果class之间的继承关系是private,编译器不会自动将一个derived class对象转换为一个base class对象。
由private继承而来的所有成员,在derived class中都会变成private属性。
private继承纯粹是一种实现技术。private继承意味着只有实现部分被继承,而接口部分应略去。
private继承一位置is-implemented-in-terms-of,与复合相同。
应尽可能的使用复合,必要时才使用private继承(当需要访问另一个类的protected成员,或需要重新定义一个或多个virtual函数时)。
例子见Item39
Item40 明智而审慎的使用多重继承
技术上,如果一个类同时public继承一个class和private继承一个class可以获得is-a和is-implemented-in-terms-of两种效果。但个人认为在实际应用中,不要使用多重继承。
Item36 绝不重新定义继承来的non-virtual函数
non-virtual函数都是静态绑定的。这意思是说,由于pB被声明为一个point-to-B,通过pB调用的non-virtual函数永远是B所定义的版本,即使pB指向一个类型为”B派生之class”的对象。
但另一方面,虚函数确实动态绑定的。所以它们不受这个问题之苦。
任何情况下都不应该重新定义一个继承而来的non-virtual函数。
#include "BD.h" void main() { //pB和pD都是指向对象D,但pB->mf()和pD->mf()却分别调用了B::mf()和D::mf().容易导致错乱的发生 D x; B* pB = &x; pB->mf(); D* pD = &x; pD->mf(); return; }
例子见Item36
Item37 绝不重新定义继承而来的缺省参数值
virtual函数系动态绑定,而缺省参数值却是静态绑定。
对象的所谓静态类型,就是它在程序中被声明时所采用的类型。对象的所谓动态类型,则是指目前所指对象的类型。
因此,若重新定义继承而来的缺省参数值(virtual函数),则会发生错乱。若用基类指针指向派生类,则在调用函数时,会发生函数执行的是派生类的方法,却使用的是基类的默认参数。
若将派生类的参数定义为和基类一样,不但代码重复,且代码带着相依性。
当virtual函数需要默认参数时,最好的方法是使用NVI手法。另non-virtual函数调用virtual函数。将默认参数提取到non-virtual函数中。virtual函数不需要定义默认参数。
可以看到,同样的Circle对象的draw方法,产生的结果不一样。一次为绿色,一次为红色。这增加了混乱程度。需要利用NVI方式整改,整改的结果可参考例子。
#include "Circle.h" int main() { Circle c; c.draw(); Shape *s = new Circle(); s->draw(); return 0; }
例子见Item37
Item38 通过复合塑模出has-a或“根据某物实现出”
复合的意义和public继承完全不同.
在应用域,复合意味着has-a,在实现域,复合意味着is-implemented-in-terms-of.
Item35中的stragegy策略就体现着复合的设计.
Item39 明智而审慎的使用private继承
如果class之间的继承关系是private,编译器不会自动将一个derived class对象转换为一个base class对象。
由private继承而来的所有成员,在derived class中都会变成private属性。
private继承纯粹是一种实现技术。private继承意味着只有实现部分被继承,而接口部分应略去。
private继承一位置is-implemented-in-terms-of,与复合相同。
应尽可能的使用复合,必要时才使用private继承(当需要访问另一个类的protected成员,或需要重新定义一个或多个virtual函数时)。
例子见Item39
Item40 明智而审慎的使用多重继承
技术上,如果一个类同时public继承一个class和private继承一个class可以获得is-a和is-implemented-in-terms-of两种效果。但个人认为在实际应用中,不要使用多重继承。
相关文章推荐
- Effective C++读书笔记(十一)继承与面向对象设计部分(下)
- Effective C++读书笔记(十一)继承与面向对象设计部分(下)
- Effective C++读书笔记(十一)继承与面向对象设计部分(下)
- Effective C++ 精要(第六部分:继承与面向对象设计)
- Effective C++读书笔记(十)继承与面向对象设计部分(上)
- Effective C++读书笔记(十)继承与面向对象设计部分(上)
- Effective C++读书笔记(十)继承与面向对象设计部分(上)
- Effective C++读书笔记(十)继承与面向对象设计部分(上)
- Effective C++读书笔记 第六部分 继承与面向对象设计
- OC基础-零基础学习Objective-C:第二部分.封装、继承和多态
- C++(6)继承与面向对象设计
- 6.继承与面向对象设计
- C++部分——C++继承和多态(1)
- Prototype源码浅析——Class部分(二)之继承
- vb.net之旅(十一)可视继承
- [文件系统]文件系统学习笔记(十一)——部分代码详解
- C 语言部分实现面向对象的继承特性
- Swift-下标脚本和继承(Subscripts and Inheritance)(十一)
- 继承与面向对象设计
- Java进阶(十一)部分数据类型取值范围