1. 程式人生 > >c++primer第五版----學習筆記(十八)Ⅱ

c++primer第五版----學習筆記(十八)Ⅱ

部分習題解答:

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() {}
};