C++编程思想 答案 第十一章 其他章节点击用户名找 thinking in C++ annotated solution guidecharpter 11.docx
《C++编程思想 答案 第十一章 其他章节点击用户名找 thinking in C++ annotated solution guidecharpter 11.docx》由会员分享,可在线阅读,更多相关《C++编程思想 答案 第十一章 其他章节点击用户名找 thinking in C++ annotated solution guidecharpter 11.docx(20页珍藏版)》请在冰点文库上搜索。
C++编程思想答案第十一章其他章节点击用户名找thinkinginC++annotatedsolutionguidecharpter11
[ViewingHints][BookHomePage][FreeNewsletter]
[Seminars][SeminarsonCDROM][Consulting]
AnnotatedSolutionGuide
Revision1.0
forThinkinginC++,2ndedition,Volume1
byChuckAllison
©2001MindView,Inc.AllRightsReserved.
[PreviousChapter][TableofContents][NextChapter]
Chapter11
11-1
Turnthe“bird&rock”codefragmentatthebeginningofthischapterintoaCprogram(usingstructsforthedatatypes),andshowthatitcompiles.NowtrytocompileitwiththeC++compilerandseewhathappens.
(Lefttothereader)
11-2
Takethecodefragmentsinthebeginningofthesectiontitled“ReferencesinC++”andputthemintoamain().Addstatementstoprintoutputsothatyoucanprovetoyourselfthatreferencesarelikepointersthatareautomaticallydereferenced.
(Lefttothereader)
11-3
Writeaprograminwhichyoutryto
(1)Createareferencethatisnotinitializedwhenitiscreated.
(2)Changeareferencetorefertoanotherobjectafteritisinitialized.(3)CreateaNULLreference.
(Lefttothereader)
11-4
Writeafunctionthattakesapointerargument,modifieswhatthepointerpointsto,andthenreturnsthedestinationofthepointerasareference.
(Lefttothereader)
11-5
Createaclasswithsomememberfunctions,andmakethattheobjectthatispointedtobytheargumentofExercise4.Makethepointeraconstandmakesomeofthememberfunctionsconstandprovethatyoucanonlycalltheconstmemberfunctionsinsideyourfunction.Maketheargumenttoyourfunctionareferenceinsteadofapointer.
(Lefttothereader)
11-6
Takethecodefragmentsatthebeginningofthesectiontitled“Pointerreferences”andturnthemintoaprogram.
(Lefttothereader)
11-7
Createafunctionthattakesanargumentofareferencetoapointertoapointerandmodifiesthatargument.Inmain(),callthefunction.
(Lefttothereader)
11-8
Createafunctionthattakesachar&argumentandmodifiesthatargument.Inmain(),printoutacharvariable,callyourfunctionforthatvariable,andprintitoutagaintoprovetoyourselfthatithasbeenchanged.Howdoesthisaffectprogramreadability?
Solution:
//:
S11:
CallByRef.cpp
#include
voidnextc(char&c){
staticcharletter='a';
c=letter++;
}
intmain(){
usingnamespacestd;
charc='z';
cout<<"c=="<nextc(c);
cout<<"c=="<nextc(c);
cout<<"c=="<}
/*Output:
c==z
c==a
c==b
*/
///:
~
ACprogrammerwillfinditverystrangeindeedthatcischangedinmain(),sinceapointerwasn’tpassed.Pass-by-referencesemanticshavesideeffectsandshouldbeusedsparingly.Agoodexampleisistream:
:
get(char&c).Sincestreamfunctionsreturnareferencetothestreamitselfsoyoucanimmediatelytestitforend-of-file,thecharacterextractedfromtheinputstreamisstoredviathereferenceargumentc.
11-9
Writeaclassthathasaconstmemberfunctionandanon-constmemberfunction.Writethreefunctionsthattakeanobjectofthatclassasanargument;thefirsttakesitbyvalue,thesecondbyreference,andthethirdbyconstreference.Insidethefunctions,trytocallbothmemberfunctionsofyourclassandexplaintheresults.
(Lefttothereader)
11-10
(Somewhatchallenging)Writeasimplefunctionthattakesanintasanargument,incrementsthevalue,andreturnsit.Inmain(),callyourfunction.Nowdiscoverhowyourcompilergeneratesassemblycodeandtracethroughtheassemblystatementssothatyouunderstandhowargumentsarepassedandreturned,andhowlocalvariablesareindexedoffthestack.
(Lefttothereader)
11-11
Writeafunctionthattakesasitsargumentsachar,int,float,anddouble.Generateassemblycodewithyourcompilerandfindthestatementsthatpushtheargumentsonthestackbeforeafunctioncall.
(Lefttothereader)
11-12
Writeafunctionthatreturnsadouble.Generateassemblycodeanddeterminehowthevalueisreturned.
(Lefttothereader)
11-13
ProduceassemblycodeforPassingBigStructures.cpp.Tracethroughanddemystifythewayyourcompilergeneratescodetopassandreturnlargestructures.
(Lefttothereader)
11-14
Writeasimplerecursivefunctionthatdecrementsitsargumentandreturnszeroiftheargumentbecomeszero,otherwiseitcallsitself.Generateassemblycodeforthisfunctionandexplainhowthewaythattheassemblycodeiscreatedbythecompilersupportsrecursion.
(Lefttothereader)
11-15
Writecodetoprovethatthecompilerautomaticallysynthesizesacopy-constructorifyoudon’tcreateoneyourself.Provethatthesynthesizedcopy-constructorperformsabitcopyofprimitivetypesandcallsthecopy-constructorofuser-definedtypes.
Solution:
//:
S11:
AutoCopy.cpp
#include
usingnamespacestd;
classInner{
doublex;
public:
Inner(doublex){
this->x=x;
}
Inner(constInner&i2){
x=i2.x;
cout<<"Inner:
:
Inner(constInner&)\n";
}
doublegetX()const{
returnx;
}
};
classOuter{
Innerm;
intn;
public:
Outer(doublex,inti):
m(x),n(i){}
voidprint(){
cout<<'('<}
};
intmain(){
Outero1(10.0,20);
o1.print();
Outero2(o1);
o2.print();
}
/*Output:
(10,20)
Inner:
:
Inner(constInner&)
(10,20)
*/
///:
~
ClassOutercontainsaninstanceofclassInnerandanint,butithasnocopyconstructor,sothecompilerwillbuildoneforus.ClassInnerhasacopyconstructorthatannouncesitselfsoyoucanseethatitexecutes,andthesubsequentcalltoOuter:
:
print()alsorevealsthattheintmemberwascopiedcorrectly.
11-16
Writeaclasswithacopy-constructorthatannouncesitselftocout.Nowcreateafunctionthatpassesanobjectofyournewclassinbyvalueandanotheronethatcreatesalocalobjectofyournewclassandreturnsitbyvalue.Callthesefunctionstoprovetoyourselfthatthecopy-constructorisindeedquietlycalledwhenpassingandreturningobjectsbyvalue.
Solution:
//:
S11:
TraceCopies.cpp
#include
usingnamespacestd;
classTrace{
intn;
public:
Trace(intn){
cout<<"Trace:
:
Trace("<this->n=n;
}
Trace(constTrace&t){
cout<<"Trace:
:
Trace(constTrace&)\n";
n=t.n;
}
intgetN()const{
returnn;
}
};
voidf(Tracet){
cout<<"f("<}
Traceg(){
Tracet
(2);
returnt;
}
Traceh(intn){
returnn;
}
intmain(){
Tracet1=1;
f(t1);
Tracet2=g();
Tracet3=h(3);
}
/*Output:
*CompilerA:
Trace:
:
Trace
(1)
Trace:
:
Trace(constTrace&)
f
(1)
Trace:
:
Trace
(2)
Trace:
:
Trace(constTrace&)
Trace:
:
Trace(constTrace&)
Trace:
:
Trace(3)
Trace:
:
Trace(constTrace&)
*CompilerB:
Trace:
:
Trace
(1)
Trace:
:
Trace(constTrace&)
f
(1)
Trace:
:
Trace
(2)
Trace:
:
Trace(constTrace&)
Trace:
:
Trace(3)
*/
///:
~
Simplydefineacopyconstructorthatannouncesitself.Rememberthatifyoudefineanyconstructoratall(includingacopyconstructor),thecompilerwillnotsynthesizeadefaultconstructorforyou,soIneededtodefinesomeconstructorotherthanthecopyconstructorsoIcancreateTraceobjects.IchosetotakeanintargumentsoIcanbettertracethroughthehiddenoperations.
CompilerAperformsnooptimizationssoyoucanseeallthepossibleoperations.Thefirstlineisthecreationoft1,andthenexttwoarethecallthatpassest1tof().Thecalltog()invokestwocallstothecopyconstructor:
onetocreatethereturnvalue,andanothertoinitializet2withthatvalue.Noticethath()returnsaTraceobjectbyvalue,butinsteadofusingthecopyconstructoritusesthesingle-argconstructorthattakesanint.That’sbecausewe’reaskingthecompilertocreateaTraceobjectfromanint.Thebottomlineis,wheneveranobjectiscreated,someconstructoriscalled;whichonedependsonthecontext.
CompilerBisalotsmarterthanCompilerAwhenitcomestocreatingcopies.
11-17
Createaclassthatcontainsadouble*.Theconstructorinitializesthedouble*bycallingnewdoubleandassigningavaluetotheresultingstoragefromtheconstructorargument.Thedestructorprintsthevaluethat’spointedto,assignsthatvalueto-1,callsdeleteforthestorage,andthensetsthepointertozero.Nowcreateafunctionthattakesanobjectofyourclassbyvalue,andcallthisfunctioninmain().Whathappens?
Fixtheproblembywritingacopy-constructor.
Solution:
//:
S11:
ShallowCopy.cpp
#include
usingnamespacestd;
classHasPointer{
double*p;
public:
HasPointer(doublex){
p=newdouble(x);
}
~HasPointer(){
cout<<"~HasPointer()\n";
deletep;
}
voidprint(){
cout<<*p<}
};
voidf(HasPointerhp)
{
hp.print();
}
intmain(){
HasPointerhp(5);
f(hp);
}
/*Output:
5
~HasPointer()
~HasPointer()
!
!
>
*/
///:
~
(Asasidenote,noticethatyoucanuseconstructorsyntaxtoinitializebuilt-intypesinnewexpressions,asintheconstructorforHasPointer.)
Whenyoucallf(hp),acopyofhpispassedtof(),thedestructorofwhichexecuteswhenthatcopyisnolongerneeded.Problemis,thedestructordeletesp,sowhenthedestructorrunsagaintodestroyhpasmain()completes,ittriestodeletepasecondtime!
ThesolutionistohavethecompilerperformadeepcopyofHasPointerobjectsviaanappropriatecopyconstructor,suchas:
HasPointer(constHasPointer&rhs){
p=newdouble(*rhs.p);
}
Asarule,aclasswithapointermemberprobablyneedsacopyconstructor(andasyou’llseeinthenextchapter,anappropriateassignmentoperatortoo).
11-18
Createaclasswithaconstructorthatlookslikeacopy-construct