1. 程式人生 > >《深度探索C++物件模型》讀書筆記(一)

《深度探索C++物件模型》讀書筆記(一)

Lippman早期在貝爾實驗室,和C++發明者Bjarne Stroustrup設計了全世界第一套C++編譯器cfront,還著有經典的C++入門書Ensential C++C++ Primer

全書基本以cfront的設計方法為基礎,討論編譯器如何處理C++程式碼語意,看完C++ Primer只能學會C++語法,讀完這本則可以瞭解C++面向物件的底層實現原理,簡直重新整理對C++的全新認識。

1. 關於物件

封裝成class後的空間佈局成本

  • 成員函式在class內宣告,但不出現在object中。
  • 每一個非內聯的成員函式只會誕生一個函式例項。
  • 每一個擁有“擁有零個或一個定義”的行內函數會在每一個使用者身上產生一個函式例項。

因此封裝沒有帶來空間或執行時的不良後果,實際上C++在layout以及access time上的額外代價是由virtual引起:

  • 虛擬函式機制:實現執行時繫結。(需要儲存vtbl和通過vtbl找函式地址)
  • 虛基類機制:實現多次出現在繼承體系中的基類,有一個單一而被共享的例項。(????)

簡單物件模型:

  • object記憶體放指向成員的指標,不存放成員。
  • 犧牲空間和執行時的效率。解決成員型別不一致帶來的儲存空間不一致問題。

簡單物件模型

表格驅動物件模型:

  • 需要兩個表,資料成員表和成員函式表,資料成員表直接存放資料本身,成員函式表存放每個函式的地址。
  • object存放這指向這兩個表的指標。
  • 成員函式表的思想可以支援虛擬函式實現。

表格驅動模型

C++物件模型

  • Stroustrup設計,從簡單物件模型派生而來。
  • 非靜態資料成員存放在每一個class object之內,靜態資料成員存放在個別的class object之外。
  • 靜態和非靜態的成員函式也存放在個別的class object之外。
  • 虛擬函式則通過虛擬函式表vtbl和指向虛擬函式表的指標vptr實現:
    • 每個class object有一個vptr,指向相關的vtbl。
    • vptr的設定由類的構造/析構/拷貝函式完成。
    • vtbl表第一項是每個class關聯的type_info object(用來支援執行時型別識別RTTI),其他的每一項存放著指向虛擬函式的地址。

這裡寫圖片描述

關於指標和引用:

  • 一個指標,無論指向哪一種資料型別,指標本身的所需記憶體大小是固定的(一個機器地址大小)。
  • 不同指向型別的指標的差異,在於其定址出來的object型別不同。指標型別告訴編譯器如何解釋某個特定地址中的記憶體內容從及其大小。
  • 因此指標的轉換,本質上是編譯器指令,並不改變一個指標的真正地址,改變的是編譯器對被指記憶體的解釋方式。
  • 引用通常是編譯器用一個指標實現的,但這個實現在語言層面對程式設計師做了透明化處理,所以指標和引用並沒有本質的區別。

一個class object的大小包括:

  • 非靜態資料成員的總和大小。
  • 由於對齊需要而填補的空間。
  • 為了支援virtual而由內部產生的額外開銷。

多型只能由指標或引用(而不能通過例項物件)來實現,根本原因在於:

  • 指標和引用(通常以指標來實現)的大小是固定的(一個 word),而物件的大小卻是可變的。其類的指標和引用可以指向(或引用)子類,但是基類的物件永遠也只能是基類,沒有變化則不可能引發多型。
  • 一個指標或引用絕不會引發任何“與型別有關的記憶體委託操作”,在指標型別轉換時會受到的改變的只有它們所指向記憶體的解釋方式而已。(例如指標絕不會引發空間的slice,因為它們大小相同)