您的位置:首页 > 编程语言 > C语言/C++

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函数。

#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两种效果。但个人认为在实际应用中,不要使用多重继承。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: