C编程思想 答案其他章节点击用户名找 thinking in C annotated solution guidecharpter_第1页
C编程思想 答案其他章节点击用户名找 thinking in C annotated solution guidecharpter_第2页
C编程思想 答案其他章节点击用户名找 thinking in C annotated solution guidecharpter_第3页
C编程思想 答案其他章节点击用户名找 thinking in C annotated solution guidecharpter_第4页
C编程思想 答案其他章节点击用户名找 thinking in C annotated solution guidecharpter_第5页
已阅读5页,还剩21页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 Viewing Hints Book Home Page Free Newsletter Seminars Seminars on CD ROM Consulting Annotated Solution GuideRevision 1.0for Thinking in C+, 2nd edition, Volume 1by Chuck Allison©2001 MindView, Inc. All Rights Reserved. Previous Chapter Table of Contents Next Chapter Chapter 1414-1Modify Car.cp

2、p so that it also inherits from a class called Vehicle, placing appropriate member functions in Vehicle (that is, make up some member functions). Add a nondefault constructor to Vehicle, which you must call inside Cars constructor.14-2Create two classes, Aand B,with default constructors that announc

3、e themselves. Inherit a new class called C from A, and create a member object of Bin C, but do not create a constructor for C. Create an object of class Cand observe the results.14-3Create two classes, Aand B,with default constructors that announce themselves. Inherit a new class called C from A, an

4、d create a member object of Bin C, but do not create a constructor for C. Create an object of class Cand observe the results.Solution:/: S14:DefaultConstruction.cpp#include <iostream>using namespace std;class A public: A() cout << "A:A()n"class B public: B() cout << "

5、;B:B()n"class C : public A B b;int main() C c;/* Output:A:A()B:B()*/:The “parts” of a C object are automatically constructed, inherited sub-objects first, followed by contained objects.14-4Create a three-level hierarchy of classes with default constructors, along with destructors, both of which

6、 announce themselves to cout. Verify that for an object of the most derived type, all three constructors and destructors are automatically called. Explain the order in which the calls are made.Solution:/: S14:HierarchyConstruction.cpp#include <iostream>using namespace std;class A public: A() c

7、out << "A:A()n" A() cout << "A:A()n"class B : public A public: B() cout << "B:B()n" B() cout << "B:B()n"class C : public B public: C() cout << "C:C()n" C() cout << "C:C()n"int main() C c;/* Output:A:A()B:

8、B()C:C()C:C()B:B()A:A()*/:An objects “parts” are always constructed before the object itself. Applying this principle recursively requires that the sub-object at the top of the hierarchy must be created first. Destruction is always the reverse order of construction.(Exercises 14-5 through 14-8 are l

9、eft to the reader.)14-5In Combined.cpp, create a class D that inherits from B and has a member object of class C. Add code to show when the constructors and destructors are being called.14-6Modify Order.cpp to add another level of inheritance Derived3 with member objects of class Member4 and Member5

10、. Trace the output of the program.14-7In NameHiding.cpp, verify that in Derived2, Derived3, and Derived4, none of the base-class versions of f( ) are available.14-8Modify NameHiding.cpp by adding three overloaded functions named h( ) to Base, and show that redefining one of them in a derived class h

11、ides the others.14-9Inherit a class StringVector from vector<void*> and redefine the push_back( ) and operator member functions to accept and produce string*. What happens if you try to push_back( ) a void*?Solution:/: S14:StringVector.cpp/-msc VC+ only fakes reinterpret_cast#include <iostr

12、eam>#include <vector>#include <string>#include <cstddef> / For size_tusing namespace std;class StringVector : public vector<void*> public: void push_back(string* s) vector<void*>:push_back(s); string*& operator(size_t n) return reinterpret_cast<string*> (ve

13、ctor<void*>:operator(n); const string* operator(size_t n) const return reinterpret_cast<const string*> (vector<void*>:operator(n); ;int main() StringVector v; string s1("live"), s2("long"), s3("and"), s4("prosper"); v.push_back(&s1); v.pu

14、sh_back(&s2); v.push_back(&s3); v.push_back(&s4); for (size_t i = 0; i < v.size(); +i) cout << *vi << endl; / void* p = &s1; / v.push_back(p); / error!/* Output:livelongandprosper*/:The problem with the commented-out push_back( ) above is that there is no implicit conv

15、ersion from a void* to any other type, as there is in C. This makes StringVector type-safe. Note that I overloaded both versions of operator (const and non-const).If youve done any amount of reading on object-oriented programming in C+, you probably have learned that you should never override a non-

16、virtual function from a publicly-inherited class (see for example, Scott Meyers “Effective C+”, Item 37). The standard containers such as vector have no virtual functions at all, so there must be a better way to define StringVector. The Better Way is to use private inheritance, and provide access to

17、 the inherited functions as the following version illustrates.class StringVector : private vector<void*> public: void push_back(string* s) vector<void*>:push_back(s); string*& operator(size_t n) return reinterpret_cast<string*> (vector<void*>:operator(n); const string* op

18、erator(size_t n) const return reinterpret_cast<const string*> (vector<void*>:operator(n); using vector<void*>:size;Private inheritance combined with templates makes building such type-safe containers fairly simple. (See Chapter 16 and Volume 2).(Exercises 14-10 through 14-13 are le

19、ft to the reader.)14-10Write a class containing a long and use the psuedo-constructor call syntax in the constructor to initialize the long.14-11Create a class called Asteroid. Use inheritance to specialize the PStash class in Chapter 13 (PStash.h & PStash.cpp) so that it accepts and returns Ast

20、eroid pointers. Also modify PStashTest.cpp to test your classes. Change the class so PStash is a member object.14-12Repeat Exercise 11 with a vector instead of a PStash.14-13In SynthesizedFunctions.cpp, modify Chess to give it a default constructor, copy-constructor, and assignment operator. Demonst

21、rate that youve written these correctly.14-14Create two classes called Traveler and Pager without default constructors, but with constructors that take an argument of type string, which they simply copy to an internal string variable. For each class, write the correct copy-constructor and assignment

22、 operator. Now inherit a class BusinessTraveler from Travelerand give it a member object of type Pager. Write the correct default constructor, a constructor that takes a string argument, a copy-constructor, and an assignment operator.Solution:/: S14:BusinessTraveler.cpp#include <iostream>#incl

23、ude <string>using namespace std;class Traveler string str;public: Traveler(const string& s) : str(s) Traveler(const Traveler& t) : str(t.str) Traveler& operator=(const Traveler& t) if (this != &t) str = t.str; return *this; string getString() const return str; ;class Pager

24、string str;public: Pager(const string& s) : str(s) Pager(const Pager& p) : str(p.str) Pager& operator=(const Pager& p) if (this != &p) str = p.str; return *this; string getString() const return str; ;class BusinessTraveler : public Traveler Pager pager;public: BusinessTraveler()

25、: Traveler(""), pager("") BusinessTraveler(const string& t, const string& p) : Traveler(t), pager(p) BusinessTraveler(const BusinessTraveler& b) : Traveler(b), pager(b.pager) BusinessTraveler& operator=(const BusinessTraveler& b) if (this != &b) Traveler:o

26、perator=(b); / Assign base part pager = b.pager; / Assign derived part return *this; friend ostream& operator<<(ostream& os, const BusinessTraveler& b) return os << """ << b.getString() << "", "" << b.pager.getString() <

27、< """ ;int main() BusinessTraveler b1("Joe BusinessMan", "Pager 1"); cout << b1 << endl; BusinessTraveler b2("Jane BusinessWoman", "Pager 2"); cout << b2 << endl; BusinessTraveler b3; cout << b3 << endl; Bu

28、sinessTraveler b4(b1); cout << b4 << endl; b3 = b2; cout << b3 << endl;/* Output:"Joe BusinessMan", "Pager 1""Jane BusinessWoman", "Pager 2""", """Joe BusinessMan", "Pager 1""Jane BusinessWom

29、an", "Pager 2"*/:The solution is a little clearer if BusinessTraveler has a constructor that takes two arguments: one for the Travelers name and one for the Pager name. The key point of this exercise is to get the constructor and assignment operator correct with inheritance. Both need

30、 to make sure that the base class sub-object is taken care of (which is sometimes easy to forget!). In constructors you use the initializer list; in assignment operators you explicitly call the base class assignment operator (since the base class data is private, you have no choice).14-15Create a cl

31、ass with two static member functions. Inherit from this class and redefine one of the member functions. Show that the other is hidden in the derived class.Solution:/: S14:StaticBaseMethods.cpp#include <iostream>using namespace std;class Base public: static void f() cout << "Base:f()

32、n" static void g() cout << "Base:g()n" ;class Derived : public Base public: static void g(int) cout << "Derived:g(int)n" ;int main() Derived:f(); Derived:g(1); / Derived:g(); / Error: too few parameters/* Output:Base:f()Derived:g(int)*/:The fact that I introduced

33、 a parameter for g( ) in Derived is not significant; any function named the same as one in any base class hides all overloaded functions of the same name in the base classes (because derived classes constitute a nested scope).14-16Look up more of the member functions for ifstream. In FName2.cpp, try

34、 them out on the file object.(Left to the reader)14-17Use private and protected inheritance to create two new classes from a base class. Then attempt to upcast objects of the derived class to the base class. Explain what happens.Solution:/: S14:InaccessibleBase.cpp/=M echo Compile InaccessibleBase.c

35、pp by hand!class Base ;class Private : private Base ;class Protected : protected Base ;int main() Private pri; Protected pro; / Both statements are errors: Base* b = static_cast<Base*>(&pri); b = static_cast<Base*>(&pro);/* Output:Error Line 12: Cannot cast from 'Private *

36、9; to 'Base *' in function main()Error Line 13: Cannot cast from 'Protected *' to 'Base *' in function main()*/:Just like you cant access private or protected members in non-member or non-derived contexts (respectively), neither can you attempt an upcast to a private or prote

37、cted base class. These types of inheritance are used for implementation only, therefore, clients that only have the public interface available have no such access.14-18In Protected.cpp, add a member function in Derived that calls the protected Base member read( ).(Left to the reader.)14-19Change Pro

38、tected.cpp so that Derived is using protected inheritance. See if you can call value( ) for a Derived object.(Left to the reader.)14-20Create a class called SpaceShip with a fly( ) method. Inherit Shuttle from SpaceShip and add a land( ) method. Create a new Shuttle, upcast by pointer or reference t

39、o a SpaceShip, and try to call the land( ) method. Explain the results.Solution:/: S14:NarrowingCast.cpp/=M echo Compile NarrowingCast.cpp by hand!class SpaceShip public: void fly() ;class Shuttle : public SpaceShip public: void land() ;int main() Shuttle shut; SpaceShip& ship = static_cast<S

40、paceShip&>(shut); ship.land(); / Error!/* Output:Error Line 16: 'land' is not a member of 'SpaceShip' in function main()*/:No mystery here. The variable ship is a SpaceShip, which does not have a land( ) method. If SpaceShip had a land method, there would still be a problem: S

41、paceShip:land( ) would be called instead of Shuttle:land( ) (rarely the right thing to do!). This mystery is solved in the next chapter (read about virtual functions).(Exercises 14-21 through 14-25 are left to the reader.)14-21Modify Instrument.cpp to add a prepare( ) method to Instrument. Call prep

42、are( ) inside tune( ).14-22Modify Instrument.cpp so that play( ) prints a message to cout, and Wind redefines play( ) to print a different message to cout. Run the program and explain why you probably wouldnt want this behavior. Now put the virtual keyword (which you will learn about in Chapter 15)

43、in front of the play( ) declaration in Instrument and observe the change in the behavior.14-23In CopyConstructor.cpp, inherit a new class from Child and give it a Member m. Write a proper constructor, copy-constructor, operator=, and operator<< for ostreams, and test the class in main( ).14-24

44、Take the example CopyConstructor.cpp and modify it by adding your own copy-constructor to Child without calling the base-class copy-constructor and see what happens. Fix the problem by making a proper explicit call to the base-class copy constructor in the constructor-initializer list of the Child c

45、opy-constructor.14-25Modify InheritStack2.cpp to use a vector<string>instead of a Stack.14-26Create a class Rock with a default constructor, a copy-constructor, an assignment operator, and a destructor, all of which announce to coutthat theyve been called. In main( ), create a vector<Rock&g

46、t; (that is, hold Rock objects by value) and add some Rocks. Run the program and explain the output you get. Note whether the destructors are called for the Rock objects in the vector. Now repeat the exercise with a vector<Rock*>. Is it possible to create a vector<Rock&>?Solution:/:

47、S14:LikeARock.cpp#include <iostream>#include <vector>using namespace std;class Rock public: Rock() cout << "Rock()n" Rock(const Rock&) cout << "Rock(const Rock&)n" Rock& operator=(const Rock&) cout << "Rock()n" return *this;

48、 Rock() cout << "Rock()n" int main() vector<Rock> byValue; Rock r1, r2, r3; byValue.push_back(r1); byValue.push_back(r2); byValue.push_back(r3); cout << "byValue populatednn" vector<Rock*> byPtr; byPtr.push_back(&r1); byPtr.push_back(&r2); byPtr.pu

49、sh_back(&r3); cout << "byPtr populatednn"/* Output:Rock()Rock()Rock()Rock(const Rock&)Rock(const Rock&)Rock(const Rock&)byValue populatedbyPtr populatedRock()Rock()Rock()Rock()Rock()Rock()*/:All the standard C+ containers store a copy of their elements (hence the call

50、s to the copy constructor above). Even byPtr stores copies; theyre just copies of the pointers you sent to push_back( ). As you can also see, the destructor of byValue ensures that all its elements (copies) are destroyed. (Again, so does byPtr; pointers just dont have destructors, so you see no trac

51、e output). It makes no sense to have a vector of references, since vectors store copies. If you store heap pointers in a container, you are responsible to delete them.14-27This exercise creates the design pattern called proxy. Start with a base class Subjectand give it three functions: f( ), g( ), a

52、nd h( ). Now inherit a class Proxy and two classes Implementation1 and Implementation2 from Subject. Proxy should contain a pointer to a Subject, and all the member functions for Proxy should just turn around and make the same calls through the Subject pointer. The Proxy constructor takes a pointer

53、to a Subject that is installed in the Proxy(usually by the constructor). In main( ), create two different Proxy objects that use the two different implementations. Now modify Proxy so that you can dynamically change implementations.Solution:This is the well-known Proxy pattern from the Gang of Four

54、(see "Design Patterns", Gamma et al, Prentice-Hall, 1994). Here's a solution that allows changing the implementation at run-time:/: S14:Proxy.cpp#include <iostream>using namespace std;class Subject public: virtual void f() = 0; virtual void g() = 0; virtual void h() = 0;class Proxy : public Subject Subject* pSubject;public: Proxy(Subject* pSubject = 0) this->pSubject = pSubject; void setSubject(Subject* pSubject) this->pSubject = pSubject; void f() pSubject->f(); void g() pSubject->g(); void h() pSubject->h(); ;class Implementation1 : p

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论