最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

C++ Primer 筆記-第18章 用于大型程序的工具

2023-03-11 17:02 作者:Code有毒  | 我要投稿

18.1 異常處理

  1. 異常處理(exception handing)?機制允許程序中獨立開發(fā)的部分能夠在運行時就出現(xiàn)的問題進行通信并做出相應(yīng)的處理。

18.1.1 拋出異常

  1. 通過拋出(throwing)?一條表達式來引發(fā)(raised)一個異常。

  2. 被拋出表達式的類型以及當前的調(diào)用鏈共同決定了哪段處理代碼(handling)?將被用于處理該異常。

  3. 當執(zhí)行一個throw時,跟在throw后面的語句將不再執(zhí)行,然后進行棧展開(stack unwinding)。棧展開過程沿著嵌套函數(shù)的調(diào)用鏈不斷查找,直到找到了異常匹配的catch子句為止;或者也可能一直沒找到匹配的catch,程序?qū)⒄{(diào)用標準庫函數(shù)terminate終止程序的執(zhí)行

  4. 類對象分配的資源將由類的析構(gòu)函數(shù)負責釋放。因此,如果我們使用類來控制資源的分配,就能確保無論函數(shù)正常結(jié)束還是遭遇異常,資源都能被正確地釋放。

  5. 出于棧展開可能使用析構(gòu)函數(shù)的考慮,析構(gòu)函數(shù)不應(yīng)該拋出不能被它自身處理的異常。如果析構(gòu)函數(shù)需要執(zhí)行某個可能拋出異常的操作,則該操作應(yīng)該被放置在一個try語句塊當中,并且在析構(gòu)函數(shù)內(nèi)部得到處理。

  6. 異常對象(exception object)是一種特殊的對象,編譯器使用異常拋出表達式來對異常對象進行拷貝初始化。因此,throw語句中的表達式必須擁有完全類型。當我們拋出表達式時,該表達式的靜態(tài)編譯時類型決定了異常對象的類型。

  7. 拋出指針要求在任何對應(yīng)的處理代碼存在的地方,指針所指的對象都必須存在。

18.1.2 捕獲異常

  1. catch子句(catch clause)?中的?異常聲明(exception declaration)?看起來像是只包含一個形參的函數(shù)形參列表。像在形參列表中一樣,如果?catch?無須訪問拋出的表達式的話,則我們可以忽略捕獲形參的名字。

  2. 通常情況下,如果catch接受的異常與某個繼承體系有關(guān),則最好將該catch的參數(shù)定義成引用類型。

  3. 如果在多個catch語句的類型之間存在著繼承關(guān)系,則我們應(yīng)該把繼承鏈最底端的類(most derived type)放在前面,而將繼承鏈最頂端的類(least derived type)放在后面。

  4. 一條catch語句通過重新拋出(rethrowing)的操作將異常傳遞給另一個catch語句。這里的重新拋出仍然是一條throw語句,只不過不包含任何表達式。

  5. 為了一次性捕獲所有異常,我們使用省略號作為異常聲明,這樣的處理代碼稱為捕獲所有異常(catch-all)?的處理代碼,形如?catch(...)。

  6. 如果catch(...)與其他幾個catch語句一起出現(xiàn),則catch(...)必須在最后的位置。出現(xiàn)在捕獲所有異常語句后面的catch語句將永遠不被匹配。

18.1.3 函數(shù)try語句塊與構(gòu)造函數(shù)

  1. 要想處理構(gòu)造函數(shù)初始值拋出的異常,我們必須將構(gòu)造函數(shù)寫成函數(shù)try語句塊(也稱為函數(shù)測試塊,function try block)的形式。

  2. 函數(shù)try語句塊使得一組catch語句既能處理構(gòu)造函數(shù)體(或析構(gòu)函數(shù)),也能處理構(gòu)造函數(shù)的初始化過程(或析構(gòu)函數(shù)的析構(gòu)過程)。

tempalte <typename T>

Blob<T>::Blob(std::initializer_list<T> il) try :

? ?data(std::make_shared<std::vector<T>>(il)) {

? ? ? ?// 函數(shù)載體

} catch(const std::bad_alloc& e) { handle_out_of_memory(e); }

  1. 和其他函數(shù)調(diào)用一樣,如果在參數(shù)初始化的過程中發(fā)生了異常,則該異常屬于調(diào)用表達式的一部分,并將在調(diào)用者所在的上下文中處理。

  2. 處理構(gòu)造函數(shù)初始值異常的唯一方法是將構(gòu)造函數(shù)寫成函數(shù)try語句塊。

18.1.4?noexcept異常說明

  1. c++11新標準中,可以通過提供noexcept說明(noexcept specification)?指定某個函數(shù)不會拋出異常。

void recoup(int) noexcept; ?// 不會拋出異常

void alloc(int); ? ? ? ? ? ?// 可能會拋出異常

void recoup(int) noexcept(true); ? ?// 不會拋出異常

void alloc(int) noexcept(false); ? ?// 可能拋出異常

  1. noexcept說明要么出現(xiàn)在該函數(shù)的所有聲明語句和定義語句中,要么一次也不出現(xiàn)。

  2. 編譯器不會在編譯時檢查noexcept說明。如果一個函數(shù)在說明了noexcept的同時又含有throw語句或者調(diào)用了可能拋出異常的其他函數(shù),編譯器將順利編譯通過,并不會因為這種違反異常說明的情況而報錯。

void f() noexcept(noexcept(g())); ? // f和g的異常說明一致

// noexcept有兩層含義:

// 當跟在函數(shù)參數(shù)列表后面時它是異常說明符;

// 而當作為noexcept異常說明的bool實參出現(xiàn)時,它是一個運算符。

  1. 函數(shù)指針及該指針所指的函數(shù)必須具有一致的異常說明。

  2. 如果一個虛函數(shù)承諾了它不會拋出異常,則后續(xù)派生出來的虛函數(shù)也必須做出同樣的承諾;與之相反,如果基類的虛函數(shù)允許拋出異常,則派生類的對應(yīng)函數(shù)既可以允許拋出異常,也可以不允許拋出異常。

18.2 命名空間

  1. 多個庫將名字放置在全局命名空間中將引發(fā)命名空間污染(namespace pollution)

  2. 命名空間(namespace)為防止名字沖突提供了更加可控的機制。

18.2.1 命名空間定義

  1. 和其他名字一樣,命名空間的名字也必須在定義它的作用域內(nèi)保持唯一。命名空間既可以定義在全局作用域內(nèi),也可以定義在其他命名空間中,但是不能定義在函數(shù)或類的內(nèi)部。

  2. 命名空間作用域后無須分號。

  3. 每個命名空間都是一個作用域。

  4. 定義多個類型不相關(guān)的命名空間應(yīng)該使用單獨的文件分別表示每個類型(或關(guān)聯(lián)類型構(gòu)成的集合)。

  5. 我們不把#include放在命名空間內(nèi)部。如果我們這么做了,隱含的意思是把頭文件中所有的名字定義成該命名空間的成員。

  6. 模板特例化必須定義在原始模板所屬的命名空間中。和其他命名空間名字類似,只要我們在命名空間中聲明了特例化,就能在命名空間外部定義它了。

  7. 全局作用域中定義的名字(既在所有類,函數(shù)及命名空間之外定義的名字)也就是定義在全局命名空間(global namespace)?中。全局作用域中定義的名字被隱式地添加到全局命名空間中。

  8. 作用域運算符同樣可以用于全局作用域的成員,因為全局作用域是隱式的,所以它沒有名字:::member_name表示全局命名空間中的一個成員。

  9. 嵌套的命名空間是指定義在其他命名空間中的命名空間。

  10. c++11新標準引入了一種新的嵌套命名空間,稱為內(nèi)聯(lián)命名空間(inline namespace)。

  11. 內(nèi)聯(lián)命名空間中的名字可以被外層命名空間直接使用。也就是說,我們無須在內(nèi)聯(lián)命名空間的名字前添加表示該命名空間的前綴,通過外層命名空間的名字可以直接訪問它。

  12. 未命名的命名空間(unnamed namespace)?是指關(guān)鍵字namespace后緊跟花括號括起來的一些列聲明語句。未命名的命名空間中定義的變量擁有靜態(tài)的生命周期:它們在第一次使用前創(chuàng)建,并且直到程序結(jié)束才銷毀。

  13. 和其他命名空間不同,未命名的命名空間僅在特定的文件內(nèi)部有效,其作用范圍不會橫跨多個不同的文件。

  14. 定義在未命名的命名空間中的名字可以直接使用,畢竟我們找不到什么命名空間的名字來限定它們;同樣的,我們也不能對未命名的命名空間的成員使用作用域運算符。

  15. 一個未命名的命名空間也能嵌套在其他命名空間當中。此時,未命名的命名空間中的成員可以通過外層命名空間的名字來訪問。

  16. 在文件中進行靜態(tài)聲明的做法已經(jīng)被c++標準取消了,現(xiàn)在的做法是使用未命名的命名空間。

18.2.2 使用命名空間成員

  1. 命名空間的別名(namespace alias)?使得我們可以為命名空間的名字設(shè)定一個短得多的同義詞。一個命名空間可以有好幾個同義詞或別名,所有別名都與命名空間原來的名字等價。

  2. 一條?using聲明(using-declaration)?語句一次只引入命名空間的一個成員:using std::cout

  3. 一條using聲明語句可以出現(xiàn)在全局作用域、局部作用域、命名空間作用域以及類的作用域中。

  4. using指示(using directive)?和?using?聲明類似的地方是,我們可以使用命名空間名字的簡寫形式:using std;和using聲明不同的地方是,我們無法控制哪些名字是可見的,因為所有名字都是可見的。

  5. using指示使得某個特定的命名空間中所有的名字都可見,這樣我們就無須再為它們添加任何前綴限定符了。

  6. 如果我們提供了一個對std等命名空間的using指示而未做任何特殊控制的話,將重新引入由于使用了多個庫而造成的名字沖突問題。

  7. using指示一般被看作是出現(xiàn)再最近的外層作用域中。

  8. 頭文件如果再其頂層作用域中含有using指示或using聲明,則會將名字注入到所有包含了該頭文件的文件中。頭文件最多只能在它的函數(shù)或命名空間內(nèi)使用using指示或using聲明。

  9. 在命名空間本身的實現(xiàn)文件中就可以使用using指示。

18.2.3 類、命名空間與作用域

  1. 可以從函數(shù)的限定名推斷出查找名字時檢查作用域的次序,限定名以相反次序指出被查找的作用域。

  2. 當我們給函數(shù)傳遞一個類類型的對象時,除了在常規(guī)的作用域查找外,還會查找實參所屬的命名空間。

18.2.4 重載與命名空間

  1. using聲明語句聲明的是一個名字,而非一個特定的函數(shù)。

  2. 當我們?yōu)楹瘮?shù)書寫using聲明時,該函數(shù)的所有版本都被引入到當前作用域中。

  3. using指示將命名空間的成員提升到外層作用域中,如果命名空間的某個函數(shù)與該命名空間所屬作用域的函數(shù)同名,則命名空間的函數(shù)將被添加到重載集合中。

  4. 如果存在多個using指示,則來自每個命名空間的名字都會成為候選函數(shù)集的一部分。

18.3 多重繼承與虛繼承

  1. 多重繼承(multiple inheritance)?是指從多個直接基類中產(chǎn)生派生類的能力。多重繼承的派生類繼承了所有父類的屬性。

18.3.1 多重繼承

  1. 基類的構(gòu)造順序與派生類列表中基類的出現(xiàn)順序保持一致,而與派生類構(gòu)造函數(shù)初始值列表中基類的順序無關(guān)。

  2. 在c++11新標準中,允許派生類從它的一個或幾個基類中繼承構(gòu)造函數(shù)。但是如果從多個基類中繼承了相同的構(gòu)造函數(shù)(既形參列表完全相同)則程序?qū)a(chǎn)生錯誤。

  3. 如果一個類從它的多個基類中繼承了相同的構(gòu)造函數(shù),則這個類必須為該構(gòu)造函數(shù)定義它自己的版本。

  4. 析構(gòu)函數(shù)的調(diào)用順序正好與構(gòu)造函數(shù)相反。

18.3.2 類型轉(zhuǎn)換與多個基類

  1. 與只有一個基類的繼承一樣,對象、指針和引用的靜態(tài)類型決定了我們能夠使用哪些成員。

18.3.3 多重繼承下的類作用域

  1. 在多重繼承的情況下,相同的查找過程在所有直接基類中同時進行。如果名字在多個基類中都被找到,則對該名字的使用將具有二義性。

  2. 當一個類擁有多個基類時,有可能出現(xiàn)派生類從兩個或更多基類中繼承了同名成員的情況。此時,不加前綴限定符直接使用該名字將發(fā)生二義性。

18.3.4 虛繼承

  1. 虛繼承(virtual inheritance)?的目的是令某個類做出聲明,承諾愿意共享它的基類。其中,共享的基類子對象稱為虛基類(virtual base class)?。在這種機制下,不論虛基類在繼承體系中出現(xiàn)了多少次,在派生類中都只包含唯一一個共享的虛基類子對象。

  2. 使用虛繼承的類層次是由一個人或一個項目組一次性設(shè)計完成的。對于一個獨立開發(fā)的類來說,很少需要基類中的某一個是虛基類,況且新基類的開發(fā)者也無法改變已存在的類體系。

  3. 虛派生只影響從指定了虛基類的派生類中進一步派生出的類,它不會影響派生類本身。

  4. 不論基類是不是虛基類,派生類對象都能被可訪問基類的指針或引用操作。

// 關(guān)鍵字public 和 virtual 的順序隨意

class Raccoon : public virtual ZooAnimal { ... }

class Bear : virtual public ZooAnimal { ... }

18.3.5 構(gòu)造函數(shù)與虛繼承

  1. 在虛派生中,虛基類是由最低層的派生類初始化的。

  2. 含有虛基類的對象的構(gòu)造順序與一般的順序稍有區(qū)別:首先使用提供給最低層派生類構(gòu)造函數(shù)的初始值初始化該對象的虛基類子部分,接下來按照直接基類在派生類列表中出現(xiàn)的次序依次對其進行初始化。

  3. 虛基類總是先于非虛基類構(gòu)造,與它們在繼承體系中的次序和位置無關(guān)。

  4. 一個類可以有多個虛基類。此時,這些虛的子對象按照它們在派生列表中出現(xiàn)的順序從左向右依次構(gòu)造。


C++ Primer 筆記-第18章 用于大型程序的工具的評論 (共 條)

分享到微博請遵守國家法律
手游| 浮山县| 老河口市| 历史| 凌源市| 古丈县| 丽水市| 凤山市| 旅游| 郴州市| 三河市| 北流市| 利辛县| 若尔盖县| 西林县| 正镶白旗| 贺州市| 正安县| 茶陵县| 岐山县| 衡阳县| 武鸣县| 锦屏县| 黄陵县| 闻喜县| 金寨县| 岢岚县| 长乐市| 许昌市| 灵宝市| 京山县| 诸暨市| 大连市| 滨海县| 额济纳旗| 读书| 科技| 巩留县| 益阳市| 金华市| 汝州市|