第12章类
【84】12.27下面的陈述中哪个是不正确的?为什么?
a)类必须提供至少一个构造函数
不正确,因为类也可以不提供构造函数,这时使用由编译器合成的默认构造函数;
b)默认构造函数的形参列表中没有形参
不正确,因为为所有形参都提供了默认实参的构造函数也定义了默认构造函数,而这样的构造函数形参列表中是有形参的;
c)如果一个类没有有意义的默认值,则该类不应该提供默认构造函数
不正确,因为如果一个类没有默认构造函数(指的是该类提供了构造函数,但是没有提供自己的默认构造函数),则在编译器需要隐式使用默认构造函数的环境中,该类就不能使用。所以,如果一个类定义了其他构造函数,则通常也应该提供一个默认构造函数;
d)如果一个类没有定义默认构造函数,则编译器会自动生成一个,同时将每个数据成员初始化为相关类型的默认值。
不正确,因为编译器合成的默认构造函数不是将每个数据成员初始化为相关类型的默认值,而是使用与变量初始化相同的规则来初始化成员:类类型的成员执行各自的默认构造函数进行初始化;内置和复合类型的成员,只对定义在全局作用域中的对象才初始化;
【85】12.28将构造函数设置为explicit的好处是什么?缺点是什么?
答:好处是可以避免因隐式类型转换而带来的错误;缺点是当用户的确需要进行相应的类型转换时,不能依靠隐式类型转换,必须显示地创建临时对象。
【86】12.29解释在下面的定义中所发生的操作。
stringnull_isbn=”0-999 9999 9”;
首先调用接受一个C风格字符串形参的string构造函数,创建一个临时的string对象,然后调用string类的复制构造函数将null_isbn初始化为该临时对象的副本。
Sales_itemnull(null_isbn);
使用string对象null_isbn为实参,调用Sales_item类的构造函数创建Sales_item对象null。
Sales_itemnull(“0-999 9999 9”);
首先调用接受一个C风格字符串形参的string构造函数,创建一个临时的string对象,然后使用该临时对象为实参,调用Sales_item类的构造函数创建Sales_item对象null。
【87】12.30编译如下代码:
f(const_vector<int>&);
intmain(){
vector<int>v2;
f(v2);//ok!
f(42);//error!
return0;
}
基于对f的第二个调用中出现的错误,我们可以对vector构造函数作出什么推断?如果该调用成功了,那么你能得出什么结论?
答:可以用单个实参调用的构造函数定义从形参类型到该类类型的隐式转换,如果这样的构造函数被声明为explicit,则编译器不使用它作为转换操作符。函数f的形参为const vector<int>&类型,如果实参为vector<int>类型或能够隐式转换为vector<int>类型,则函数调用成功。因此,基于对f的第二个调用中出现的错误,我们可以对vector构造函数作出如下推断:vector中没有定义接受一个int型参数的构造函数,或者即使定义了接受一个int型参数的构造函数,该构造函数也被设置为explicit。
如果该调用成功了,则说明vector中定义了接受一个int型参数的非explicit构造函数。
【88】12.42下面的static数据声明和定义中哪些是错误的?
//example.h
classExample{
public:
staticdouble rate=6.5;
staticconst int vecSize = 20;
staticvector<double> vec(vecSize);
};
//example.c
#include“example.h”
doubleExample::rate;
vector<double>Example::vec;
答:类的定义体中对static成员rate和vec的初始化是错误的。因为非const static成员的初始化必须放在定义体的外部。example.c文件中对static成员rate和vec的定义也是错误的,因为此处必须给出初始值。可更正为:
//example.h
classExample{
public:
staticdouble rate;
staticconst int vecSize = 20;
staticvector<double> vec;
};
//example.c
#include“example.h”
doubleExample::rate=6.5;
//constint Example::vecSize;
vector<double>Example::vec(vecSize);