14.14 练习
部分练习题的答案可以在本书的电子文档“Annotated Solution Guide for Thinking in C++”中找到,只需支付很少的费用就可以在http://www.BruceEckel.com得到这个电子文档。
14-1 修改Car.cpp,使它也继承Vehicle类,在Vehicle中放置合适的成员函数(也就是说,补充一些成员函数)。对Vehicle增加一个非默认的构造函数,在Car的构造函数内部必须调用它。
14-2 创建两个类,A和B,带有默认的构造函数。从A继承出一个新类,称为C,并且在C中创建B的一个成员对象,而不对C创建构造函数。创建类C的一个对象,观察结果。
14-3 创建一个三层的类结构,带有默认的构造函数和析构函数,它们都对cout做了声明。对于最底层的派生类对象,验证所有三个构造函数和析构函数都自动被调用。解释这里调用的顺序。
14-4 修改Combined.cpp,再多继承一层并且增加一个新的成员对象。添加代码来显示何时调用构造函数和析构函数。
14-5 在Combined.cpp中,创建从类B继承来的类D,它含有一个类C的成员对象。添加代码来显示何时调用构造函数和析构函数。
14-6 修改Order.cpp,再继承出一层,即Derived3,它含有类Member4和类Member5的成员对象。跟踪程序的输出。
14-7 在NameHiding.cpp中验证,Derived2、Derived3和Derived4中f()的基类版本都是不可用的。
14-8 修改NameHiding.cpp,在Base中增加三个名为h()的重载函数。然后显示在派生类中重新定义其中的一个函数,则会隐藏其余的函数。
14-9 从vector<void>中继承出类StringVector,重新定义push_back()和operator[]成员函数以接收和生成string。如果试着push_back()一个void*,会发生什么情况?
14-10 创建一个包含long型成员的类,对构造函数使用psuedo构造函数调用语法来初始化这个long成员。
14-11 创建类Asteroid,使用继承,具体在第13章(PStash.h&PStash.cpp)中的PStash类,使得它接受和返回Asteroid指针。修改PStashtest.cpp并测试该类。改变这个类使得PStash是一个成员对象。
14-12 使用vector来代替PStash,重复练习11。
14-13 在SynthesizedFunctions.cpp中,修改Chess,使它有一个默认构造函数、拷贝构造函数和赋值运算符。显示我们进行了正确的修改。
14-14 创建两个不含有默认构造函数的类Traveler和Pager,但具有一个参数为string的构造函数,该构造函数只是简单地把string参数拷贝至一个内部变量中。对于每个类,创建正确的拷贝构造函数和赋值运算符。现在从Traveler中继承出类BusinessTraveler,并使其包含一个类Pager的对象。创建正确的默认构造函数、参数为string的构造函数、拷贝构造函数和赋值运算符。
14-15 创建含有两个static成员函数的类。继承这个类,并且重新定义其中一个成员函数,显示出另一个函数在派生类中被隐藏。
14-16 找出ifstream更多的成员函数。在FName2.cpp中,尝试将它们输出在file对象上。
14-17 使用private和protected继承方式从基类中创建两个新类。然后试着把派生类的对象向上类型转换为基类对象。解释所发生的事情。
14-18 在Protected.cpp中,在Derived里增加一个成员函数,它用来调用Base类中的protected成员函数read()。
14-19 修改Protected.cpp使得Derived是按protected方式继承来的。看看一个Derived对象是否可以调用value()。
14-20 创建一个含有fly()方法的类SpaceShip。从SpaceShip中继承出Shuttle,并且增加一个方法land()。创建一个新的类Shuttle,通过一个SpaceShip对象的指针或引用向上类型转换,并且试着调用land()方法。解释操作的结果。
14-21 修改Instrument.cpp,对Instrument增加一个prepare()方法。在tune()中调用prepare()。
14-22 修改Instrument.cpp,使play()向cout打印出消息,并且Wind重新定义了play(),使之向cout打印出不同的消息。运行这个程序并解释为什么我们不希望有这样的结果。然后在Instrument中play()的声明前加上virtual关键字(我们将在第15章中学习),观察结果有什么不同。
14-23 在CopyConstructor.cpp中,由Child继承出一个新类,使其具有一个Member m。并且创建适当的构造函数、拷贝构造函数、operator=和用于ostreams的operator<<。在main()中测试这个类。
14-24 修改例子CopyConstructor.cpp,对Child使用我们自己的拷贝构造函数,它不调用基类拷贝构造函数,看看有什么情况发生。在Child的拷贝构造函数中的初始化列表里,通过进行适当的显式地对基类拷贝构造函数的调用来分析和解决这个问题。
14-25 使用vector<string>代替Stack,来对InheritStack2.cpp进行修改。
14-26 创建一个类Rock,含有默认构造函数、拷贝构造函数、赋值运算符和析构函数,它们都向cout声明它们已经被调用。在main()中,创建一个vector<Rock>(即通过传值方式得到Rock对象)并且添加一些Rock对象。运行这个程序并解释我们得到的输出。注意vector里所有Rock的析构函数是否都被调用了。然后用vector<Rock*>来重复上面的操作。可以创建vector<Rock&>吗?
14-27 本练习创建一个名为代理(proxy)的设计模式。首先建立一个基类Subject,使其包含三个函数f()、g()和h()。现在从中继承出类Proxy和另外两个类Implementation1和Implementation2。Proxy中应包含指向Subject的指针,于是它的所有成员函数可以通过该Subject指针指回,调用Subject的函数。Proxy的构造函数的参数是指向Subject的指针,它被包含在Proxy内(通常这由构造函数完成)。在main()中,使用两种不同的实现方式创建两个不同的Proxy对象。然后修改Proxy使得我们可以动态地改变实现方式。
14-28 修改第13章的ArrayOperatorNew.cpp以显示,如果我们继承Widget,则仍将可以正确地执行分配。解释为什么不能正确地执行第13章中Framis.cpp的继承。
14-29 修改第13章的Framis.cpp,对Framis进行继承,并且为我们的派生类创建新版本的new和delete。表明可以正确地运行它们。