9.10 练习
9-1 创建一个基类X,这个类包含具有一个int型参数的一个构造函数、一个返回类型为void的无参成员函数f()。现在从基类X派生出类Y和Z,并为它们各自创建一个具有一个int型参数的构造函数。然后,再从类Y和Z派生出类A。创建类A的一个对象,并且为这个对象调用f()。利用显式消除二义性的方法来解决问题。
9-2 以练习9-1的结果作为开始,创建一个指向基类X的名为px的指针,将前面创建的类A的对象地址赋值给px。利用虚基类解决这个问题。现在调整基类X,这样就不必再为X内部的A调用构造函数。
9-3 以练习9-2的结果作为开始,删除对f()使用显式消除二义性的方法,并且看看是否可以通过px调用f()。跟踪它看看哪个函数被调用了。解决这个问题,使得在类的继承层次结构中可以调用正确的函数。
9-4 与一个makeNoise()函数声明一起,构造一个Animal接口类。与savePersonFromFire()函数声明一起,构造一个SuperHero接口类。在这两个接口类中放置一个move()函数声明。(记住构造接口的方法是使用纯虚函数。)现在定义3个单独的类:SuperlativeMan、Amoeba(一个性情无常的超级英雄)和TarantulaWoman;当Amoeba和Tarantula Woman实现Animal和SuperHero接口的时候,SuperlativeMan实现SuperHero的接口。定义两个全局函数animalSound(Animal)和saveFromFire(SuperHero)。寻求用这两个函数能够通过每个接口调用相应对象的所有方法。
9-5 重复上面的练习,但是利用模板而不是继承来实现接口,就像在Interfaces2.cpp中做的那样。
9-6 定义若干代表超级英雄(superhero)能力的具体的混入类(例如StopTrain、BendSteel和ClimbBuilding等)。重新完成练习9-4,从这些混入类中派生出SuperHero派生类,并且调用它们的成员函数。
9-7 利用模板重复上面的练习,用强大的超级英雄(superhero)混入类作为模板参数。利用模板强大的功能更好地为其他类服务。
9-8 从练习9-4中撤销Animal接口,重新定义Amoeba使其仅实现SuperHero。现在定义一个从两个类SuperlativeMan和Amoeba继承来的SuperlativeAmoeba类。试着将SuperlativeAmoeba对象作为参数传递给saveFromFire()。为了让上面的调用正确进行,需要做些什么?如何使用虚继承来改变对象的长度?
9-9 继续上面的练习,为练习9-4的SuperHero增加一个整型strengthFactor数据成员,并在构造函数中对其进行初始化。在3个派生类中也加入构造函数来初始化strengthFactor。在SuperlativeAmoeba中,必须要做哪些不同的工作?
9-10 继续上面的练习,分别给两个类SuperlativeMan和Amoeba(但不包括SuperlativeAmoeba)增加一个eatFood()成员函数,这样两个版本的eatFood()函数获得不同的食物对象的类型(所以这两个函数的识别标志不同)。在SuperlativeAmoeba中调用两个eatFood()函数中的任一个时必须做哪些工作?为什么?
9-11 为SuperlativeAmoeba定义一个能够正确工作的输出流插入符和赋值操作符。
9-12 从层次结构中删除SuperlativeAmoeba,并且修改Amoeba使它派生自两个类SuperlativeMan(它也是由SuperHero派生)和SuperHero。在SuperHero和SuperlativeMan(采用完全相同的识别标志)中实现一个虚函数workout(),并且以Amoeba对象调用这个函数。哪个函数被调用了?
9-13 用组合而非继承重新定义SuperlativeAmoeba,使它的行为类似于SuperlativeMan或Amoeba。利用转换运算符提供隐式向上类型转换。将这种方法和继承方法进行比较。
9-14 假设有一个预先编译好的Person类(即只有头文件和编译好的目标文件)。假设Person还有一个非虚函数work()。通过从Person派生和使用Person:work()的一个实现,让SuperHero能够成为一个行为适度且遵守规矩的普通的Person,而让SuperHero:work()成为虚函数。
9-15 定义一个引用计数错误的日志混入类ErrorLog,持有一个静态文件流,可以用这个流发送消息。当引用计数大于零时该类打开流,当引用计数归零时(始终附加在文件上)关闭流。让多个类的对象能够向静态日志流发送消息。通过ErrorLog中的跟踪语句,观察流的打开和关闭。
9-16 修改BreakTie.cpp,在其中加入派生(非虚派生)自Bottom的名为VeryBottom的类。除非在using中对f的声明将“左”变为“右”,VeryBottom应该看起来就和Bottom一样。修改main()函数,实例化一个VeryBottom而非Bottom对象。请问,将调用哪个f()?