部分习题解答:
18.1:
(a)range_error
(b)exception
如果写成throw p,则抛出指针,是错误的
18.2:
发生异常,所在块之前的临时变量都会被销毁,v调用vector类的析构函数进行销毁,并释放相关内存;p指针会被销毁,但p指向的内存是动态分配的,所以该内存不会被销毁,输入流对象会调用ifstream类的析构函数进行销毁,最终程序被终止
18.3:
我们要解决的问题是p指向的内存要被自动释放
第一种使用智能指针,并传入lambda表达式:
shared_ptr<int> p(new int[v.size(), [](int *p){ delete [] p;} );
第二种构建一个包含int*类,并在析构函数中delete指针:
class intAr {
int *p;
public:
intAr(size_t n) : p(new int[n]) {}
~intAr()
{
delete [] p;
}
};
18.4:
继承链最底端的类须放在前面,将顺序倒过来即可
18.5:
#include <iostream>
#include <cstdlib>
using namespace std;
int main(int argc, char **argv)
{
try {
}
catch (overflow_error o) {
cout << o.what() << endl;
abort();
}
catch (underflow_error u) {
cout << u.what() << endl;
abort();
}
catch (range_error r) {
cout << r.what() << endl;
abort();
}
catch (domain_error d) {
cout << d.what() << endl;
abort();
}
catch (invalid_argument i) {
cout << i.what() << endl;
abort();
}
catch (out_of_range o) {
cout << o.what() << endl;
abort();
}
catch (length_error l) {
cout << l.what() << endl;
abort();
}
catch (runtime_error r) {
cout << r.what() << endl;
abort();
}
catch (logic_error l) {
cout << l.what() << endl;
abort();
}
catch (bad_cast b) {
cout << b.what() << endl;
abort();
}
catch (bad_alloc b) {
cout << b.what() << endl;
abort();
}
catch (exception e) {
cout << e.what() << endl;
abort();
}
system("pause");
return 0;
}
18.6:
(a)throw &exception();
(b)任意异常
(c)throw int();
18.7:
将所有的构造函数添加这个try语句块
template <typename T>
Blob<T>::Blob(std::initializer_list<T> il) try : data(std::make_shared<std::vector<T>>(il)) {
/*...*/
}catch (const std::bad_alloc &e){
std::cerr << e.whar() << std::endl;
}
18.9:
#include <iostream>
#include <string>
//18.9
struct out_of_stock :public std::runtime_error
{
explicit out_of_stock(const std::string &s) :std::runtime_error(s) {}
};
struct isbn_mismatch :public std::logic_error
{
explicit isbn_mismatch(const std::string &s) :std::logic_error(s) {}
isbn_mismatch(const std::string &s, const std::string &ls, const std::string &rs)
:std::logic_error(s), left(ls), right(rs)
{}
std::string left;
std::string right;
};
18.10:
不捕获异常就会发生异常,程序报错并终止
18.11:
what负责返回用于初始化异常对象的信息,如what抛出异常可能造成无限递归
18.13:
希望定义的对象、函数、类类型或其他实体,它只在程序的一小段代码中可见,因为这样可以更进一步地缓解名字空间污染问题;在标准c++引入命名空间之前,用static进行静态声明,现在只使用未命名空间
18.14:
mathLib::MatrixLib::matrix mathLib::MatrixLib::operator*(const matrix &, const matrix &);
18.15:
using指示以关键字using开始,后面是关键字namespace以及命名空间的名字,using指示将命名空间中所有名字变得可见
using声明一次只引入命名空间的一个成员,两者作用域范围相同
18.16、18.17:
namespace Exercise {
int ivar = 0;
double dvar = 0;
const int limit = 1000;
}
int ivar = 0;
//1.1
using Exercise::ivar;//错误,与全局变量ivar冲突,多次声明
using Exercise::dvar;
using Exercise::limit;
void manip()
{
double dvar = 3.1416; //覆盖using声明中的dvar
int iobj = limit + 1;
++ivar;
++::ivar;
}
//1.2
void manip()
{
using Exercise::ivar; //隐藏全局变量
using Exercise::dvar;
using Exercise::limit;
double dvar = 3.1416; //错误,多次定义
int iobj = limit + 1;
++ivar;
++::ivar;
}
//2.1
using namespace Exercise;
void manip()
{
double dvar = 3.1416; //覆盖using中的dvar
int iobj = limit + 1;
++ivar; //错误,不明确,产生二义性
++::ivar;
}
//2.2
void manip()
{
using namespace Exercise;
double dvar = 3.1416; //覆盖using中的dvar
int iobj = limit + 1;
++ivar; //错误,不明确,产生二义性
++::ivar;
}
18.18:
如mem1是string,则在string类中查找swap函数,找到则不使用std版本,若为int类型,则直接使用标准库中swap版本
18.19:
只能使用标准库版本swap
18.20:
namespace primerLib {
void compute(); //不可行
void compute(const void *); //可行,0->NULL
}
using primerLib::compute;
void compute(int); //可行
void compute(double, double = 3.4); //可行,int->double
void compute(char*, char* = 0); //可行,0->NULL
void f() {
compute(0); //与compute(int)最佳匹配
}
//2.0
namespace primerLib {
void compute(); //不可行,可见
void compute(const void *); //可行,0->NULL,可见
}
void compute(int); //可行,被隐藏
void compute(double, double = 3.4); //可行,int->double,被隐藏
void compute(char*, char* = 0); //可行,0->NULL,被隐藏
void f() {
using primerLib::compute;
compute(0); //与compute(const void *)最佳匹配
}
18.21:
(a)正确,公有继承CAD,私有继承Vehicle
(b)错误,继承相同的基类
(c)正确
18.22:
构造函数执行顺序:A->B->C->X->Y->Z->MI
18.23:
可以令一个基类指针或引用指向一个派生类对象
(a)允许 (b)允许
(c)允许 (d)允许
18.24:
所有属于Bear类的成员将不能进行访问,只能访问属于ZooAnimal的成员
18.25:
#include <iostream>
using namespace std;
class Base1 {
public:
virtual void print()
{
cout << "Base1::print()" << endl;
}
virtual ~Base1()
{
cout << "~Base1()" << endl;
}
};
class Base2 {
public:
virtual void print()
{
cout << "Base2::print()" << endl;
}
virtual ~Base2()
{
cout << "~Base2()" << endl;
}
};
class D1 : public Base1 {
public:
void print()
{
cout << "D1:print()" << endl;
}
~D1()
{
cout << "~D1()" << endl;
}
};
class D2 : public Base2 {
public:
void print()
{
cout << "D2.print()" << endl;
}
~D2()
{
cout << "~D2()" << endl;
}
};
class MI : public D1, public D2 {
public:
void print()
{
cout << "MI::print()" << endl;
}
~MI()
{
cout << "~MI()" << endl;
}
};
int main()
{
Base1 *pb1 = new MI;
Base2 *pb2 = new MI;
D1 *pd1 = new MI;
D2 *pd2 = new MI;
pb1->print();c //以下三个都是调用MI::print()
pd1->print();
pd2->print();
delete pb2; //以下三个都是调用MI的析构,调用D2的析构,调用Base2的析构,调用D1的析构,调用Base1的析构
delete pd1;
delete pd2;
return 0;
}
18.26:
参数为42(int),调用产生二义性,可以修改为
MI.Base1::print(42);
加上前缀限定符,直接调用Base1的成员
18.27:
(a)
Base1: ival,dval,cval,print
Base2: fval,print
Derived: sval,dval,print
MI: ival,dvec,print,foo
还有在foo中定义的ival
(b)
dval: Base1::dval, Derived::dval, MI成员函数foo中定义的dval
ival: Base1::ival, MI::ival
cval: Base1::cval, 形参cval
(c)
dval = Base1::dval + Derived::dval;
(d)
Base2::fval = MI::dvec.back();
(e)
Derived::sval[0] = Base1::cval;
18.28:
需要加限定符:foo(),cval
不需要加限定符:bar(),ival
18.29:
(a)
构造顺序:Class、Base、D1、D2、MI、Final
析构顺序相反
(b)
一个Base部分,2个Class部分
(c)
1、错误,Class是Base的基类,而pb是Base类 2、正确,基类Class可以指向所有子类
3、错误、pb是Base类,MI是Base的子类 4、正确、D2是MI的基类
18.30:
class Class {};
class Base : public Class {
protected:
int val;
public:
Base() : val(0),Class() { }
Base(const Base &a) = default;
Base(int a) : val(a),Class() {}
};
class D1 : virtual public Base {
public:
D1() :Base() {}
D1(const D1 &b) = default;
D1(int a) :Base(a) {}
};
class D2 :public virtual Base {
public:
D2() :Base() {}
D2(const D2 &b) = default;
D2(int a) :Base(a) {}
};
class MI :public D1, public D2 {
public:
MI() {}
MI(const MI &m) :Base(m), D1(m), D2(m) {}
MI(int i) :Base(i), D1(i), D2(i) {}
};
class Final :public MI, public Class {
public:
Final() {}
Final(const Final &f) : Base(f), MI(f), Class() {}
Final(int i) : Base(i), Class() {}
};