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