1. 程式人生 > >C++物件模型 筆記1

C++物件模型 筆記1

C++類中的函式不會佔用類本身的記憶體,而是類的宣告的非行內函數只會誕生一個函式體。C++在佈局和存取時間上主要的額外負擔由virtual引起:

  • virtual function機制 執行期動態繫結
  • virtual base class機制 多次繼承中,單一的基類被共享

C++的基本面向物件模型:

  • 所有的非靜態資料成員存放到class內部
  • 靜態成員和函式存放到class外部

虛擬函式的支援步驟:

  • 每個class產生一些指向virtual function的指標,存放在一個表格中,稱為虛表,virtual table
    vtbl
  • 每個class新增一個指標,指向相關的vtbl,稱為vptr

該方式的好處是空間和存取時間效率高,缺點在於如果程式程式碼沒變,但是class的非靜態成員改變了,那麼程式碼就要重新編譯。

虛擬繼承情況下,不管發生多少次繼承,永遠只有一個基類。可以理解為一個bptr,有點在於減少二義性,缺點在於時空表現的效率低。

C++支援多型的方式,僅僅使用下列方法是安全的:

  • 使用指標的操作,子類的指標可以指向基類:

    shape *ps = new circle();  // circle是shape的子類
    
  • 使用virtual function機制:

    ps->rotate();   // 呼叫實際的函式
    
  • 使用dynamic_casttypeid運算子:

    if (circle *pc = dynamic_cast<circle*>(ps) ) ...
    

多型最主要的用法是使用共同的介面進行封裝,一般來說這個介面定義在一個抽象的基類中。這就像Java的interface關鍵字,不過C++沒有介面的具體關鍵字,實際中可以使用多重繼承虛基類來完成,在執行期進行檢查到底是執行哪一個子類的函式。

動態繫結操作會在傳入引用和指標的時候發生。

一個class object佔用記憶體的大小取決於下面三個:

  • 非靜態成員總和的大小
  • 需要alignment
    的需求而padding的空間
  • 為了支援virtual而產生的空間,主要是各種虛表。對於指標(不包含智慧指標)來說,它們佔用的記憶體大小是固定的。

如果把子類轉換成基類,那麼子類會被切割,只保留基類的部分。

只有下面4種情況下,才會有自動生成的預設建構函式:

  • 如果一個class沒有建構函式,而它的成員含有預設建構函式,此時會產生一個建構函式,不過合成操作只有真正需要呼叫時才會發生。
  • 基類由預設建構函式,派生類沒有定義建構函式,此時會合成一個預設建構函式,而且會呼叫基類的建構函式,根據宣告的次序執行
  • 帶有virtual functionclass。 當一個class宣告(或繼承)一個virtual functionclass派生自一個繼承串鏈,其中有一個或者多個虛基類
  • 帶有虛基類的類

必須使用引數初始化列表的情況:

  • 初始化引用物件
  • 初始化const物件
  • 呼叫基類的建構函式,且建構函式擁有一組引數
  • 呼叫類成員的建構函式,而且有引數

初始化列表的順序不一定按照宣告的順序執行,這點要格外注意!!!一般來說,很多時候初始化列表的效率更高,因此在意義明確的情況下,儘量使用初始化列表!!!