本文答案,部分参考于C++ Primer 习题集
前面章节的习题答案
配套的学习资料
https://www.jianguoyun.com/p/DTK5uJgQldv8CBjKv80D
18.1
(a) 异常对象r的类型是range_error
(b) 被抛出的异常对象是对指针p解引用的结果,其类型与p的静态类型相匹配.为exception.若写成throw p.则抛出的异常对象是exception *类型.
读者可尝试编译,运行这几条语句,观察系统的提示.
18.2
在new操作后发生的异常使得动态分配的数组没有被撤销,从而造成内存泄漏.
18.3
void exercise(int *b,int *e){
itn *p=new int[v.size()];
try{
ifstream in("line");
}catch{
delete p;
}
}
18.4
修改为:
try{
}
catch(overflow_error eobj){
}
catch(const runtime_error &re){
}catch(exception){}
18.5
int main(){
try{
}
catch(const exception &e){
cerr<<e.what()<<endl;
abort();
}
return 0;
}
18.6
(a) throw new exceptionType();
(b) throw 8;
(c) throw 11;
18.7
18.8
class MyTest_Base {
public:
MyTest_Base() {
cout << "开始准备销毁一个MyTest_base类型的对象" << endl;
//把异常完全封装在析构函数内部
try {
throw std::exception("在析构函数中故意抛出一个异常,测试! ");
}
catch (.) {
}
}
void Func()throw() {
throw std::exception("故意抛出一个异常,测试!");
}
void Other() {}
};
18.9
Sales_data& Sales_data::operator-=(const Sales_data& rhs) {
if (isbn() != rhs.isbn())
throw isbn_mismatch("wrong isbns", isbn(), rhs.isbn());
units_sold -= rhs.units_sold;
revenue -= rhs.revenue;
return *this;
}
18.10
Sales_data item1, item2, sum;
while (cin>>item1>>item2) {
try {
sum = item1 + item2;
return sum;
}
catch (const isbn_mismatch& e) {
cerr << e.what() << ": left isbn(" << e.left << ") right isbn(" << e.right << ")" << endl;
}
}
Sales_data item1, item2, sum;
while (cin >> item1 >> item2) {
sum = item1 + item2;
return sum;
}
18.11
what 函数是在catch异常后提取基本信息的虚函数,what函数是确保不会抛出任何异常的.如果what函数抛出了异常,则会在新产生的异常中由于what函数继续产生异常,将会产生异常的死循环.所以what函数必须确保不抛出异常.
18.12
将Query类似以及Query_base的类层次定义为命名空间chapter15的成员,并相应修改主函数中的代码(使用限定名引用这些类,或者使用相关的声明).
18.13
通常,当需要和声明局部与文件的实体时,可以使用未命名的命名空间,即在文件的最外层作用域中定义未命名的命名空间.
18.14
mathLib::MatrixLib::matrix mathLib::matrixLib::operator *(const matrix &,const matrix &);
18.15
一个using 指令使得特定命名空间中的所有名字都为空间的;而一个using声明只能引入特定命名空间的一个成员.
18.16
18.17
18.18
如果mem1是string类型,编译器除了在常规作用域中查找匹配的swap外,还会查找string所属的命名空间是否有string类型特定版本的swap函数,但对string而言,找到的就是std::swap,完成两个字符串内容的交换.
若meme1是int类型,由于int是内置类型,没有特定版本的swap,只会在常规作用域中查找,由于using声明的作用,最终会调用std::swap,完成两个int的交换.
18.19
将直接使用标准库版本的swap,而不会查找特定版本的swap或常规作用域中的其他swap.
18.20
18.21
(b) 错误,在一个派生类列表中,同一基类只能出现一次,这里List出现了两次.
18.22
(1) A的构造函数
(2) B的构造函数
(3)C的构造函数
(4) X的构造函数
(5) Y的构造函数
(6) Z的构造函数
(7) MI的构成函数
18.23
因为C对B的继承是私有继承,使得在D中B的默认构造函数成为不可访问的.所以尽管存在从"D*“到"B*”,以及从"D*"到"A*"的转换,但这些转换不可访问.
18.24
如果使用ZooAnimal指针,则只能使用ZooAnimal类中定义的操作。
pb->print(count);通过基类指针调用虚函数,使用动态绑定,pb目前指向Panda对象,随意调用Panda::print(ostream&).
pb->cuddle();因为ZooAnimal类中没有定义cuddle操作,所以该调用出错.
pb->highlight();因为zooAnimal类中没有定义highlight操作,所以该调用出错.
delete pb;因为ZooAnimal类中定义了虚析构函数,所以Panda类中的析构函数也是虚函数,因此delete pb;通过虚机制调用Panda析构函数,随着Panda析构函数的执行.依次调用Endangered,Bear和ZooAnimal的析构函数.
所以,通过指向Panda对象的Bear指针或ZooAnimal指针进行上述调用.将以同样方式确定函数调用.
18.25
a,b,c都是通过基类指针调用虚函数print,这些基类指针当前都指向Mi类对象,所以都调用Mi::print(); d,e,f都通过基类指针删除对象这些基类指针当前都指向Mi类对象,所以都通过虚机制调用Mi析构函数,随着Mi析构函数的执行,依次调用D2,Base2,D1和Base1的析构函数.
18.26
因为mi,print(42),通过MI类对象调用print函数,编译器通过了名字查找,确定调用的是MI类中定义的print函数,但是MI类中定义的print函数需要std::vector 类型的参数,所以该调用是错误的.
改正,将MI中print的声明改为void print(int);该print调用即可正确编译和执行
18.27
(a) MI::foo中可见名字有:ival,dval,cval,sval,fval,dvec和print
(b) Dval和print
© dval=Base1::dval+Derivaed::dval;
(d) fval=dvec.back()
(e) sval[0]=cval;