1、C+编程思想 答案 第十一章 其他章节点击用户名找 thinking in C+ annotated solution guidecharpter 11 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 Allison2001 MindView, Inc. All Rights Reserved. Previ
2、ous Chapter Table of Contents Next Chapter Chapter 1111-1Turn the “bird & rock” code fragment at the beginning of this chapter into a C program (using structs for the data types), and show that it compiles. Now try to compile it with the C+ compiler and see what happens.(Left to the reader)11-2Take
3、the code fragments in the beginning of the section titled “References in C+” and put them into a main( ). Add statements to print output so that you can prove to yourself that references are like pointers that are automatically dereferenced.(Left to the reader)11-3Write a program in which you try to
4、 (1) Create a reference that is not initialized when it is created. (2) Change a reference to refer to another object after it is initialized. (3) Create a NULL reference.(Left to the reader)11-4Write a function that takes a pointer argument, modifies what the pointer points to, and then returns the
5、 destination of the pointer as a reference.(Left to the reader)11-5Create a class with some member functions, and make that the object that is pointed to by the argument of Exercise 4. Make the pointer a const and make some of the member functions const and prove that you can only call the const mem
6、ber functions inside your function. Make the argument to your function a reference instead of a pointer.(Left to the reader)11-6Take the code fragments at the beginning of the section titled “Pointer references” and turn them into a program.(Left to the reader)11-7Create a function that takes an arg
7、ument of a reference to a pointer to a pointer and modifies that argument. In main( ), call the function.(Left to the reader)11-8Create a function that takes a char& argument and modifies that argument. In main( ), print out a char variable, call your function for that variable, and print it out aga
8、in to prove to yourself that it has been changed. How does this affect program readability?Solution:/: S11:CallByRef.cpp#include void nextc(char& c) static char letter = a; c = letter+;int main() using namespace std; char c = z; cout c = c endl; nextc(c); cout c = c endl; nextc(c); cout c = c endl;/
9、* Output:c = zc = ac = b*/:A C programmer will find it very strange indeed that c is changed in main( ), since a pointer wasnt passed. Pass-by-reference semantics have side effects and should be used sparingly. A good example is istream:get(char&c). Since stream functions return a reference to the s
10、tream itself so you can immediately test it for end-of-file, the character extracted from the input stream is stored via the reference argument c.11-9Write a class that has a const member function and a non-const member function. Write three functions that take an object of that class as an argument
11、; the first takes it by value, the second by reference, and the third by const reference. Inside the functions, try to call both member functions of your class and explain the results.(Left to the reader)11-10(Somewhat challenging) Write a simple function that takes an int as an argument, increments
12、 the value, and returns it. In main( ), call your function. Now discover how your compiler generates assembly code and trace through the assembly statements so that you understand how arguments are passed and returned, and how local variables are indexed off the stack.(Left to the reader)11-11Write
13、a function that takes as its arguments a char, int, float, and double. Generate assembly code with your compiler and find the statements that push the arguments on the stack before a function call.(Left to the reader)11-12Write a function that returns a double. Generate assembly code and determine h
14、ow the value is returned.(Left to the reader)11-13Produce assembly code for PassingBigStructures.cpp. Trace through and demystify the way your compiler generates code to pass and return large structures.(Left to the reader)11-14Write a simple recursive function that decrements its argument and retur
15、ns zero if the argument becomes zero, otherwise it calls itself. Generate assembly code for this function and explain how the way that the assembly code is created by the compiler supports recursion.(Left to the reader)11-15Write code to prove that the compiler automatically synthesizes a copy-const
16、ructor if you dont create one yourself. Prove that the synthesized copy-constructor performs a bitcopy of primitive types and calls the copy-constructor of user-defined types.Solution:/: S11:AutoCopy.cpp#include using namespace std;class Inner double x;public: Inner(double x) this-x = x; Inner(const
17、 Inner& i2) x = i2.x; cout Inner:Inner(const Inner&)n; double getX() const return x; ;class Outer Inner m; int n;public: Outer(double x, int i) : m(x), n(i) void print() cout ( m.getX() , n )n; ;int main() Outer o1(10.0, 20); o1.print(); Outer o2(o1); o2.print();/* Output:(10,20)Inner:Inner(const In
18、ner&)(10,20)*/:Class Outer contains an instance of class Inner and an int, but it has no copy constructor, so the compiler will build one for us. Class Inner has a copy constructor that announces itself so you can see that it executes, and the subsequent call to Outer:print( ) also reveals that the
19、int member was copied correctly.11-16Write a class with a copy-constructor that announces itself to cout. Now create a function that passes an object of your new class in by value and another one that creates a local object of your new class and returns it by value. Call these functions to prove to
20、yourself that the copy-constructor is indeed quietly called when passing and returning objects by value.Solution:/: S11:TraceCopies.cpp#include using namespace std;class Trace int n;public: Trace(int n) cout Trace:Trace( n n = n; Trace(const Trace& t) cout Trace:Trace(const Trace&)n; n = t.n; int ge
21、tN() const return n; ;void f(Trace t) cout f( t.getN() )n;Trace g() Trace t(2); return t;Trace h(int n) return n;int main() Trace t1 = 1; f(t1); Trace t2 = g(); Trace t3 = h(3);/* Output: * Compiler A:Trace:Trace(1)Trace:Trace(const Trace&)f(1)Trace:Trace(2)Trace:Trace(const Trace&)Trace:Trace(const
22、 Trace&)Trace:Trace(3)Trace:Trace(const Trace&) * Compiler B:Trace:Trace(1)Trace:Trace(const Trace&)f(1)Trace:Trace(2)Trace:Trace(const Trace&)Trace:Trace(3)*/:Simply define a copy constructor that announces itself. Remember that if you define any constructor at all (including a copy constructor), t
23、he compiler will not synthesize a default constructor for you, so I needed to define some constructor other than the copy constructor so I can create Trace objects. I chose to take an int argument so I can better trace through the hidden operations.Compiler A performs no optimizations so you can see
24、 all the possible operations. The first line is the creation of t1, and the next two are the call that passes t1 to f( ). The call to g( ) invokes two calls to the copy constructor: one to create the return value, and another to initialize t2 with that value. Notice that h( ) returns a Trace object
25、by value, but instead of using the copy constructor it uses the single-arg constructor that takes an int. Thats because were asking the compiler to create a Trace object from an int. The bottom line is, whenever an object is created, some constructor is called; which one depends on the context.Compi
26、ler B is a lot smarter than Compiler A when it comes to creating copies.11-17Create a class that contains a double*. The constructor initializes the double* by calling new double and assigning a value to the resulting storage from the constructor argument. The destructor prints the value thats point
27、ed to, assigns that value to -1, calls deletefor the storage, and then sets the pointer to zero. Now create a function that takes an object of your class by value, and call this function in main( ). What happens? Fix the problem by writing a copy-constructor.Solution:/: S11:ShallowCopy.cpp#include u
28、sing namespace std;class HasPointer double* p;public: HasPointer(double x) p = new double(x); HasPointer() cout HasPointer()n; delete p; void print() cout *p endl; ;void f(HasPointer hp) hp.print();int main() HasPointer hp(5); f(hp);/* Output:5HasPointer()HasPointer()*/:(As a side note, notice that
29、you can use constructor syntax to initialize built-in types in new expressions, as in the constructor for HasPointer.)When you call f(hp), a copy of hp is passed to f( ), the destructor of which executes when that copy is no longer needed. Problem is, the destructor deletes p, so when the destructor
30、 runs again to destroy hp as main( ) completes, it tries to delete p a second time! The solution is to have the compiler perform a deep copy of HasPointer objects via an appropriate copy constructor, such as: HasPointer(const HasPointer& rhs) p = new double(*rhs.p); As a rule, a class with a pointer member probably needs a copy constructor (and as youll see in the next chapter, an appropriate assignment operator too).11-18Create a class with a constructor that looks like a copy-construct
copyright@ 2008-2023 冰点文库 网站版权所有
经营许可证编号:鄂ICP备19020893号-2