12.8 练习
部分练习题的答案可以在本书的电子文档“Annotated Solution Guide for Thinking in C++”中找到,只需支付很少的费用就可以从http://www.BruceEckel.com得到这个电子文档。
12-1 写一个有重载operator++的类。试着用前缀和后缀两种形式调用此运算符,看看编译器会给出什么警告。
12-2 创建含有一个int成员的简单的类,以成员函数的形式重载operator+。同时提供一个print()成员函数,以ostream&作为参数并打印出该ostream&。测试该类表明它可以正确运行。
12-3 用成员函数形式,在练习2的类中增加一个二元operator-。要求可以在a+b-c这样复杂的表达式中使用该类的对象。
12-4 在练习2的例子中增加operator++和operator—,要包括前缀和后缀版本,使得它们返回自增和自减对象。确保后缀版本返回正确的值。
12-5 修改练习4的自增和自减运算符,以使得前缀版本使用非常量而后缀版本使用常量。显示它们运行正确并解释为什么实际中要这么做。
12-6 改变练习2中的print()函数,使得它是重载operator<<,就像在IostreamOperator Overloading.cpp中一样。
12-7 修改练习3,使得operator+和operator-是非成员函数。表明它们仍能正确运行。
12-8 对练习2的类中增加一元operator-,并表明它可以正确运行。
12-9 写一个只含有单个private char成员的类。重载iostream operator<<和>>(像在IostreamOperatorOverloading.cpp中的一样)并测试它们,可以用fstreams、stringstreams和cin与cout测试它们。
12-10 测定为了前缀operator++和operator—,编译器传递的哑常量值。
12-11 写一个包含一个double成员的Number类,并增添重载的operator+、-、*、/和赋值符。为这些函数合理地选择返回值以便可以链式写表达式,以提高效率。写一个自动类型转换operator double()。
12-12 如果返回值优化还没有被使用,修改练习11,使用返回值优化。
12-13 创建一个包含指针的类,表明如果允许编译器生成operator=,结果将得到具有不同别名、指向同一存储区域的指针。现在通过定义自己的operator=解决这个问题,并表明它纠正了别名。确保检查自赋值并完全处理了此问题。
12-14 写一个包含string和static int成员的类Bird。在预设的构造函数中,根据类的名字(Bird#1,Bird#2,等等),使用int成员自动地生成一个置于string中的标识符。为ostream增加operator<<以打印Bird对象。写一个赋值operator=和一个拷贝构造函数。在main()中,验证它们都可正确运行。
12-15 写一个类BirdHouse,包含一个对象、一个指针和一个练习14中类Bird的引用。构造函数的参数是三个Bird类对象。为BirdHouse增加ostream operator<<。写一个赋值operator=和一个拷贝构造函数。在main()中,验证它们都正确地运行。确保能对BirdHouse对象链接赋值运算,并生成包括多种操作的表达式。
12-16 对练习15中的类Bird和BirdHouse增加一个int数据成员。增加成员运算符+、-、*和/,它们使用int成员在各自的成员上进行操作。验证这些工作。
12-17 用非成员运算符进行练习16的操作。
12-18 增加operator—到SmartPointer.cpp和NestedSmartPointer.cpp中。
12-19 修改CopyingVsInitialization.cpp,使得所有的构造函数打印出正在进行操作的信息。现在验证拷贝构造函数的两种调用形式是相等的。
12-20 试着为一个类创建一个非成员operator=,并看看能得到编译器的何种信息。
12-21 用拷贝构造函数创建一个类,该拷贝构造函数的第二个参数是一个预设值为“op=call.”的string成员。创建一个函数,它通过传值方式接受此类的对象,并表明拷贝构造函数被正确地调用了。
12-22 在CopyingWithPointers.cpp中,删除DogHouse中的operator=,表明编译器生成的operator=正确地拷贝了string成员,但简单地为Dog指针起了别名。
12-23 在ReferenceCounting.cpp中,增加一个static int成员和一个基本int成员作为Dog和DogHouse的数据成员。在两个类的所有构造函数中,把static int成员加1并把结果赋予基本int成员以记录所创建的对象的数目。进行必要的修改,打印出涉及的对象的int标识符。
12-24 创建包含一个string数据成员的类。在构造函数中初始化string成员,但不用创建拷贝构造函数或operator=。创建第二个类,其成员对象是第一个类的对象;同样不要为这个类创建拷贝构造函数或operator=。表明拷贝构造函数和operator=可被编译器正确地生成。
12-25 合并在OverloadingUnaryOperators.cpp和Integer.cpp中的类。
12-26 通过新增加两个Dog中的成员函数,它们无参数并返回为void值,来修改PointerToMember-Operator.cpp。创建并测试作用于这两个新函数上的重载operator->*。
12-27 在NestedSmartPointer.cpp中增加operator->*。
12-28 创建两个类Apple和Orange。在类Apple中,创建一个构造函数,其参数是Orange类的对象。然后创建一个函数,它的参数是Apple类对象,并用Orange类对象调用该函数。现在显式应用Apple类的构造函数以表明自动类型转换被禁止。修改对函数的调用,使得能成功地做显式转换。
12-29 在ReflexivityInOverloading.cpp中增加一个全局operator*并表明它具有反身性。
12-30 创建两个类并创建operator+和转换函数,使得对于这两个类,加法具有反身性。
12-31 不用自动转换运算符,而通过创建一个显式的执行类型转换的函数修改TypeConversion-Fanout.cpp。
12-32 写一段简单的代码,在其中对double类型使用operator+、-、*和/。看看编译器如何生成汇编代码并根据生成的汇编语言找出并解释发生了什么。