這篇博客來總結一下《深度探索C++物件模型》第5章構造、析構、拷貝語意學的內容,
是對主要內容的總結,原文請看原書,
1. 建構式
按照發生的順序,一個類的建構式會做的事情:
- 所有虛基類的建構式會被呼叫,從左到右,從深到淺:
- 如果虛基類被列在member initialization list(成員初始化串列)中,那么如果有任何明確指定的引數,都應該傳遞過去;如果沒有列在list中,而該類有default constructor,也應該呼叫;
- 此外,類中每一個virtual base class subobject(虛基類子物件,此處我寫為“子物件”意為其是該類的一部分)的偏移量(offset)必須在執行期可被存取(也就是虛表指標必須被設定好,其中有虛基類偏移量);
- 如果class object是最底層的(most-derived,也就是最后的派生類),其constructor可能被呼叫,某些用以支持這個行為的機制必須被放進來,
- 所有上一層的base class constructor必須被呼叫,以base class的宣告順序為順序,跟其在member iniaialization list中的順序無關;
- 如果base class被列于member initialization list中,那么任何明確指定的引數都應該被傳遞過去;
- 如果base class沒有被列于member initialization list中,而他有default constructor,那么就呼叫(書中還提到或者有default memberwise copy constructor就呼叫,沒有引數為什么呼叫拷貝建構式?我認為可能是一個錯誤);
- 如果base class是第二或后繼的base class,那么this指標需要被調整,
- 如果class object有virtual table pointer(s)(虛表指標),它們必須被設定初值,指向適當的virtual table;
- 記錄在member initialization list(成員初始化串列)中的data member(資料成員,即非靜態成員變數)初始化操作會被放進建構式本身,并以成員的宣告順序為順序(進行初始化);
- 如果某個成員變數沒有出現在member initialization list中,但在宣告時被賦予了初值,則設定此初值(或呼叫建構式)【這是我自己加的,C++11之前不允許在宣告中設定初值】;
- 如果有一個成員變數沒有出現在member initialization list中,但他有default constructor,那么會呼叫它;
- 建構式中用戶提供的陳述句被執行,
這個順序給了我們以一個啟發:那就是類的構造是從深到淺的,從內到外構造的程序就是該類從基類到派生類的提升程序,所以在建構式中盡量不要使用虛函式,因為此時類的構造可能還未結束(如果此類被一個派生類繼承,此時虛函式指標還未被正確設定),此時呼叫虛函式最多會呼叫自己定義的的虛函式和自己子類的虛函式,而外層可能的派生類定義的虛函式則不會被呼叫,
2. 物件復制語意學
一個class對于默認的copy assignment operator,在以下情況不會表現出bitwise copy(按位拷貝,就是直接拷貝)語意:
- 當class內帶一個member object,其class有一個copy assignment operator時;
- 當一個class的base class有一個copy assignment operator時;
- 當一個類宣告了任何virtual function時(我們一定不能拷貝右端class object的vptr,因為它可能是一個derived class object(派生類物件));
- 當類繼承自一個virtual base class (不論此base class有沒有copy operator,因為虛繼承也意味著一定有vptr),
3. 解構語意學
按照發生的順序,一個類的解構式會做的事情:
- 如果一個object內帶有vptr,那么首先重設相關的vptr;
- destructor的函式本身現在被執行,也就是說vptr會在用戶代碼執行前被重設(reset);
- 如果class擁有member class objects,而后者有建構式,那么它們會以其宣告的順序的相反順序被呼叫;
- 如果有任何直接的(上一層)nonvirtual base class擁有destructor,那么它們會以其宣告順序的相反順序被呼叫;
- 如果有任何virtual base class 擁有destructor,而當前討論的這個class是最尾端(most-derived)的class,那么它們會以原來的構造順序的相反順序被呼叫,
在書中作者說解構式順序是建構式順序的相反順序,因此譯者認為作者寫錯了,順序是:2, 3, 1, 4, 5,即vptr的設定放在子類析構之后,但是其實上面12345的順序是對的,
從其流程來看,和建構式一樣,我們也不應該在解構式里呼叫虛函式,因為此時vptr被設定為本類的vptr,而不是可能的派生類的vptr,
其他比如純虛函式就不說了,我覺得用處好像不是很大,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/530503.html
標籤:C++
上一篇:自定義的Qt儀表盤控制元件
