7.1 使用2.6.1节定义的Sales_data
类为1.6节的交易处理程序编写一个新版本。
答:
7.2 曾在2.6.2节的练习中编写了一个Sales_data
类,请向这个类添加combine
函数和isbn
成员。
答:
7.6 对于函数add
、read
和print
,定义你自己的版本。
答:
7.7 使用这些新函数重写7.1.2节练习中的程序。
答:
7.8 为什么read
函数将其Sales_data
参数定义成普通的引用,而print
函数将其参数定义成常量引用?
答:
因为read
函数会改变对象的内容,而print
函数不会。
7.9 对于7.1.2节练习中代码,添加读取和打印Person
对象的操作。
答:
7.10 在下面这条if
语句中,条件部分的作用是什么?
答:
read
函数的返回值是istream
对象, if
语句中条件部分的作用是从输入流中读取数据给两个data
对象。
7.11 在你的Sales_data
类中添加构造函数, 然后编写一段程序令其用到每个构造函数。
答:
7.12 把只接受一个istream
作为参数的构造函数移到类的内部。
答:
7.13 使用istream
构造函数重写第229页的程序。
答:
7.14 编写一个构造函数,令其用我们提供的类内初始值显式地初始化成员。
答:
7.15 为你的Person
类添加正确的构造函数。
答:
7.16 在类的定义中对于访问说明符出现的位置和次数有限定吗? 如果有,是什么?什么样的成员应该定义在public
说明符之后? 什么样的成员应该定义在private
说明符之后?
答:
在类的定义中对于访问说明符出现的位置和次数没有限定。
每个访问说明符指定了接下来的成员的访问级别,其有效范围直到出现下一个访问说明符或者达到类的结尾处为止。
如果某个成员能够在整个程序内都被访问,那么它应该定义为public
; 如果某个成员只能在类内部访问,那么它应该定义为private
。
7.17 使用class
和struct
时有区别吗?如果有,是什么?
答:
class
和struct
的唯一区别是默认的访问级别不同。(class默认private, struct默认public)
7.18 封装是何含义?它有什么用处?
答:
将类内部分成员设置为外部不可见,而提供部分接口给外面,这样的行为叫做封装。
用处:
- 1.确保用户的代码不会无意间破坏封装对象的状态。
- 2.被封装的类的具体实现细节可以随时改变,而无需调整用户级别的代码。
7.19 在你的Person
类中,你将把哪些成员声明成public
的? 哪些声明成private
的? 解释你这样做的原因。
答:
构造函数、getName()
、getAddress()
函数将设为public
。 name
和 address
将设为private
。 函数是暴露给外部的接口,因此要设为public
; 而数据则应该隐藏让外部不可见。
7.20 友元在什么时候有用?请分别举出使用友元的利弊。
答:
当其他类或者函数想要访问当前类的私有变量时,这个时候应该用友元。
利:与当前类有关的接口函数能直接访问类的私有变量。
弊:牺牲了封装性与可维护性。
7.21 修改你的Sales_data
类使其隐藏实现的细节。 你之前编写的关于Sales_data
操作的程序应该继续使用,借助类的新定义重新编译该程序,确保其正常工作。
答:
7.22 修改你的Person
类使其隐藏实现的细节。
答:
7.23 编写你自己的Screen
类型。
答:
7.24 给你的Screen
类添加三个构造函数:一个默认构造函数;另一个构造函数接受宽和高的值,然后将contents
初始化成给定数量的空白;第三个构造函数接受宽和高的值以及一个字符,该字符作为初始化后屏幕的内容。
答:
7.26 将Sales_data::avg_price
定义成内联函数。
答:
在头文件中加入
7.27 给你自己的Screen
类添加move
、set
和display
函数,通过执行下面的代码检验你的类是否正确。
答:
7.28 如果move
、set
和display
函数的返回类型不是Screen&
而是Screen
,则在上一个练习中将会发生什么?
答:
如果返回类型是Screen
,那么move
返回的是*this
的一个副本,因此set
函数只能改变临时副本而不能改变myScreen
的值。
7.29 修改你的Screen
类,令move
、set
和display
函数返回Screen
并检查程序的运行结果,在上一个练习中你的推测正确吗?
答:推测正确
7.30 通过this
指针使用成员的做法虽然合法,但是有点多余。讨论显示使用指针访问成员的优缺点。
答:
优点:程序的意图更明确 。函数的参数可以与成员同名,如
缺点:有时候显得有点多余,如
7.31 定义一对类X
和Y
,其中X
包含一个指向Y
的指针,而Y
包含一个类型为X
的对象。
答:
7.32 定义你自己的Screen
和Window_mgr
,其中clear
是Window_mgr
的成员,是Screen
的友元。
答:
7.38 有些情况下我们希望提供cin
作为接受istream&
参数的构造函数的默认实参,请声明这样的构造函数。
答:
7.40 从下面的抽象概念中选择一个(或者你自己指定一个),思考这样的类需要哪些数据成员,提供一组合理的构造函数并阐明这样做的原因。
答:
7.42 对于你在练习7.40中编写的类,确定哪些构造函数可以使用委托。如果可以的话,编写委托构造函数。如果不可以,从抽象概念列表中重新选择一个你认为可以使用委托构造函数的,为挑选出的这个概念编写类定义。
答:
7.43 假定有一个名为NoDefault
的类,它有一个接受int
的构造函数,但是没有默认构造函数。定义类C
,C
有一个 NoDefault
类型的成员,定义C
的默认构造函数。
答:
7.44 下面这条声明合法吗?如果不,为什么?
答:不合法。因为NoDefault
没有对应的默认构造函数。
修改如下:
7.45 如果在上一个练习中定义的vector的元素类型是C,则声明合法吗?为什么?
答:合法。因为C
有默认构造函数。
7.46 下面哪些论断是不正确的?为什么?
- (a) 一个类必须至少提供一个构造函数。
- (b) 默认构造函数是参数列表为空的构造函数。
- (c) 如果对于类来说不存在有意义的默认值,则类不应该提供默认构造函数。
- (d) 如果类没有定义默认构造函数,则编译器将为其生成一个并把每个数据成员初始化成相应类型的默认值。
答:
- (a) 不正确。如果我们的类没有显式地定义构造函数,那么编译器就会为我们隐式地定义一个默认构造函数,并称之为合成的默认构造函数。
- (b) 不完全正确。为每个参数都提供了默认值的构造函数也是默认构造函数。
- (c) 不正确。哪怕没有意义的值也需要初始化。
- (d) 不正确。只有当一个类没有定义任何构造函数的时候,编译器才会生成一个默认构造函数。
7.49 对于combine
函数的三种不同声明,当我们调用i.combine(s)
时分别发生什么情况?其中i
是一个Sales_data
,而 s
是一个string
对象。
答:
7.53 定义你自己的Debug
。
答:
7.57 编写你自己的Account
类。
答:
注:
7.58 下面的静态数据成员的声明和定义有错误吗?请解释原因。
答:
rate
应该是一个常量表达式。而类内只能初始化整型类型的静态常量,所以不能在类内初始化vec
。修改后如下