Effective C++之继承和面向对象设计

6 继承和面向对象设计

条款32:确定你的public继承塑模出is-a关系。

如果你令classD以public形式继承class B,你便是告诉C++编译器说,每一个类型为D的对象同时也是一个类型为B的对象。那么使用于base classes身上的每一件事情一定也适用于derived classes身上,因为每一个derived class对象也都是一个base class对象。

条款33:避免遮掩继承而来的名称。

Effective C++之继承和面向对象设计_第1张图片

这个读取数据的语句指涉的是local变量x,而不是global变量x,因为内层作用域的名称会掩盖外围作用域的名称。

现在导入继承,派生类作用域被嵌套在base class作用域内,像:

Effective C++之继承和面向对象设计_第2张图片

假设derived class内的mf4的实现码部分像这样:

当编译器看到这里使用名称mf2,必须估算它指涉什么东西。编译器的做法是查找各作用域。

Effective C++之继承和面向对象设计_第3张图片

base class内所有名为mf1和mf3的函数都被derived内的mf1和mf3函数遮掩掉了。

Effective C++之继承和面向对象设计_第4张图片

Effective C++之继承和面向对象设计_第5张图片

或者使用Inline转交函数

请记住:

derivedclasses内的名称会遮掩base classes内的名称。在Public继承下从来没有人希望如此。

为了让被掩盖的名称再见天日,可使用using声明式或转交函数。

条款34:区分接口继承和实现继承。

身为class的设计者,有时候你会希望derived classes只继承成员函数的接口(也就是声明);有时候你又会希望派生类同时继承函数的接口和实现,但又希望能够覆写它们所继承的实现;又有时候你希望派生类同时继承函数的接口和实现,并且不允许覆写任何东西。

Effective C++之继承和面向对象设计_第6张图片

Shape是个抽象类;他的虚函数draw使它成为一个抽象类。所有客户不能够创建它的实体。

声明一个虚函数的母的就是为了让derived classes只继承函数接口;

声明质朴(非纯)虚函数的目的,是让derived classes继承该函数的接口的缺省实现。

我们可以利用“pure virtual函数必须在derived class中重新声明,但它们可以拥有自己的实现”
Effective C++之继承和面向对象设计_第7张图片

Effective C++之继承和面向对象设计_第8张图片

声明non-virtual函数的目的是为了令derived classes继承函数的接口及一份强制性实现。

条款35:考虑virtual函数以外的其他选择。

藉由Non-Virtual Interface手法实现Template Method模式

藉由Function Pointers实现Strategy模式

藉由tr1::function完成Strategy模式

古典的Strategy模式:

Effective C++之继承和面向对象设计_第9张图片

条款36:绝不重新定义继承而来的non-virtual函数。

Effective C++之继承和面向对象设计_第10张图片

Effective C++之继承和面向对象设计_第11张图片

造成此一两面行为的原因是,non-virtual函数如B::virtual函数如B::mf和D::mf都是静态绑定。这意思是,pb被声明为一个b的指针,通过pb调用的non-virtual函数永远是B所定义的版本。

条款37:绝不重新定义继承而来的缺省参数值。

继承一个带有缺省参数值的virtual函数,virtual函数系动态绑定,而缺省参数值确实静态绑定。

所谓静态类型,就是它在程序中被声明时所采用的类型,考虑以下的class继承体系:

 

Effective C++之继承和面向对象设计_第12张图片

对象的所谓动态类型则是指“目前所指对象的类型”。也就是说,动态类型可以表现出一个对象将会有什么行为。

因为virtual函数系动态绑定,而缺省参数值确实静态绑定,所以可能有:

虽然Rectangle::draw()函数的缺省参数值应该是GREEN

条款38:通过复合塑模出has-a或“根据某物实现出”。

复合是类型之间的一种关系,当某种类型的对象内含它种类型的对象,便是这种关系。

请记住:

复合的意义和public继承完全不同;

在应用域,复合意味had-a(有一个)。在实现域,复合意味(根据某物实现出)。

 

条款39:明智而审慎的使用private继承。

如果classes之间的继承关系是Private,编译器不会自动将一个derived class对象转换为一个base class对对象。第二是,由private base class继承而来的所有成员,在derived class中都会变成private属性。

private继承纯粹只是一种实现技术。如果D以private继承了B,你的用意是为了采用B

中已经备妥的某些特性。

private继承意味着根据某物实现出。所以尽可能使用复合,必要时才使用private继承。

private继承主要用于“当一个意欲成为derived class者想访问一个意欲成为base class

者的protected成分,或为了重新定义一或多个virtual函数”。

Empty是个空类,sizeof(HoldAnInt)==sizeof(int)。这是所谓的EBO(空白基类最优化)。

和复合不用,private继承可以造成empty base最优化。这对致力于“对象尺寸最小化”

的程序库开发者而言,可能很重要。

条款40:明智而审慎的使用多重继承。

多重继承可能从一个以上的base classes继承相同名称。那会导致较多的歧义,例如:

Effective C++之继承和面向对象设计_第13张图片

两个checkouts有相同的匹配程度,没有所谓最佳匹配。为了解决:

为了防止数据重复,应该采用虚继承:

Effective C++之继承和面向对象设计_第14张图片

请记住:

多重继承比单一继承复杂。它可能导致新的歧义性,以及对virtual继承的需要。

virtual继承会增加大小,速度,初始化复杂度等等成本。如果virtualbase clases不带

任何数据,将是最具使用价值的情况。

多重继承的正当用途。其中一个情节涉及“public继承某个Interface class”和“private

继承某个协助实现的class”的两相组合。

你可能感兴趣的:(优化,function,Class,interface,编译器,Pointers)