深入理解C++的對(duì)象模型
何為C++對(duì)象模型?
C++對(duì)象模型可以概括為以下2部分:
1. 語言中直接支持面向?qū)ο蟪绦蛟O(shè)計(jì)的部分
2. 對(duì)于各種支持的底層實(shí)現(xiàn)機(jī)制
引言
現(xiàn)在有一個(gè)Point類,聲明如下:
class Point {
public:
Point(float xval);
virtual ~Point();
float x() const;
static int PointCount();
protected:
virtual ostream& print(ostream &os) const;
float _x;
static int _point_count;
};
這個(gè)類在機(jī)器上是通過什么模型來表示的呢?下面就介紹三種不同的實(shí)現(xiàn)方式。
1. 簡(jiǎn)單對(duì)象模型
簡(jiǎn)單對(duì)象模型名副其實(shí),十分簡(jiǎn)單。在簡(jiǎn)單對(duì)象模型中,一個(gè) object是由一系列slots組成,每個(gè)slot相當(dāng)于一個(gè)指針,指向一個(gè)member,memebers按照聲明的順序與slots一一對(duì)應(yīng),這里的members包括data members和function members。
如果將簡(jiǎn)單對(duì)象模型應(yīng)用在Point Class上,結(jié)構(gòu)圖如下:

優(yōu)點(diǎn):十分簡(jiǎn)單,降低了編譯器設(shè)計(jì)的復(fù)雜度。
缺點(diǎn):空間和時(shí)間上的效率降低。由于所有member都對(duì)應(yīng)一個(gè)slot指針,所以每個(gè)object在空間上額外多出:member's number 乘以指針大小的空間。同時(shí)由于訪問object的每個(gè)member都需要一次slot的額外索引,所以在時(shí)間的效率也會(huì)降低。
2. 表格驅(qū)動(dòng)對(duì)象模型
表格驅(qū)動(dòng)對(duì)象模型將member data和member function分別映射成兩個(gè)表格member data table和function member table,而object本身只存儲(chǔ)指向這兩個(gè)表格的指針。 其中function member table是由一系列的slot組成,每個(gè)slot指向一個(gè)member function; member data table則直接存儲(chǔ)的member data本身。如果將表格驅(qū)動(dòng)對(duì)象模型應(yīng)用在Point Class上,結(jié)構(gòu)圖如下:

優(yōu)點(diǎn):采用兩層索引機(jī)制,對(duì)object變化提供比較好的彈性,在object的nonstatic data member有所改變時(shí),而應(yīng)用程序代碼沒有改變,這時(shí)是不需要重新編譯的。
缺點(diǎn):空間和時(shí)間上的效率降低,具體原因可以參考簡(jiǎn)單對(duì)象模型的缺點(diǎn)分析。
3. C++ 對(duì)象模型
Stroustrup 早期設(shè)計(jì)的C++對(duì)象模型是從簡(jiǎn)單對(duì)象模型改進(jìn)而來的,并對(duì)內(nèi)存空間和存取時(shí)間進(jìn)行了優(yōu)化。主要是將nonstatic data members存儲(chǔ)在每一個(gè)object中,而static data members以及所有的function members被獨(dú)立存儲(chǔ)在所有object之外。
對(duì)虛函數(shù)的支持主要通過以下幾點(diǎn)完成的:
所有包含虛函數(shù)或者繼承自有虛函數(shù)基類的class都會(huì)有一個(gè)virtual table,該虛函數(shù)表存儲(chǔ)著一堆指向該類所包含的虛函數(shù)的指針。
每個(gè)class所關(guān)聯(lián)的type_info object也是由virtual table存儲(chǔ)的,一般會(huì)存在該表格的首個(gè)slot,type_info用于支持runtime type identification (RTTI)。
如果將C++對(duì)象模型應(yīng)用在Point Class上,結(jié)構(gòu)圖如下:

優(yōu)點(diǎn):空間和存取效率高,所有static data members以及所有的function members被獨(dú)立存儲(chǔ)在所有object之外,可以減少每個(gè)object的大小,而nonstatic data members存儲(chǔ)在每一個(gè)object中,又提升了存取效率。
缺點(diǎn):如果應(yīng)用程序的代碼未曾更改,但所用到的class的nonstatic data members有所更改,那么那些代碼仍然需要全部重新編譯,而前面的表格驅(qū)動(dòng)模型在這方面提供了較大的彈性,因?yàn)樗嗵峁┝艘粚娱g接性,當(dāng)然是付出了時(shí)間和空間上的代價(jià)。
在加上繼承情況下的對(duì)象模型
C++支持單繼承、多繼承、虛繼承,下面來看下base class實(shí)體在derived class中是如何被構(gòu)建的。
簡(jiǎn)單對(duì)象模型中可以通過derived class object中的一個(gè)slot來存儲(chǔ)base class subobject的地址,這樣就可以通過該slot來訪問base class的成員。這種實(shí)現(xiàn)方式的主要缺點(diǎn)是:因?yàn)殚g接性的存儲(chǔ)而導(dǎo)致空間和存取時(shí)間上存在額外負(fù)擔(dān);優(yōu)點(diǎn)是:derived class的結(jié)構(gòu)不會(huì)因?yàn)?code>base class的改變而改變。
表格驅(qū)動(dòng)對(duì)象模型中可以利用一個(gè)類似base class table的表格來存儲(chǔ)所有基類的信息。該表格中存儲(chǔ)一系列slot,每個(gè)slot存儲(chǔ)一個(gè)base class的地址。這種實(shí)現(xiàn)方式的缺點(diǎn)是:因?yàn)殚g接性的存儲(chǔ)而導(dǎo)致空間和存取時(shí)間上存在額外負(fù)擔(dān);優(yōu)點(diǎn)是:一是所有繼承的class都有一致的表現(xiàn)形式(包含一個(gè)base table指針,指向基類表)與基類的大小和數(shù)目沒有關(guān)系,二是base class table增加了子類的擴(kuò)展性,當(dāng)基類發(fā)生改變時(shí),可以通過擴(kuò)展、縮小或者更改base class table來進(jìn)行調(diào)整。
以上兩種實(shí)現(xiàn)方式都存在一個(gè)重要的問題,就是由于間接性而導(dǎo)致的空間和時(shí)間上的額外負(fù)擔(dān),并且該間接性的級(jí)數(shù)會(huì)隨著繼承的深度而增加。
C++ 最初采用的繼承模型并不采用任何間接性,所有基類的數(shù)據(jù)直接存儲(chǔ)在子類當(dāng)中,這樣在存儲(chǔ)結(jié)構(gòu)和訪問效率上是最高效的。當(dāng)然也有缺點(diǎn):當(dāng)base class members有任何改變,用到此base class或者derived class的對(duì)象必須重新編譯。在C++ 2.0引入了virtual base class,需要一些間接性的方式來支持該特性,一般會(huì)導(dǎo)入一個(gè)virtual base class table或者擴(kuò)展已有的virtual table。
總結(jié)
以上就是深入研究C++的對(duì)象模型的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家有所幫助。
相關(guān)文章
C++實(shí)現(xiàn)簡(jiǎn)易反彈小球游戲的示例代碼
我們利用printf 函數(shù)實(shí)現(xiàn)一個(gè)在屏幕上彈跳的小球。彈跳的小球游戲比較簡(jiǎn)單、容易入門,也是反彈球消磚塊、接金幣、臺(tái)球等很多游戲的基礎(chǔ),感興趣的可以了解一下2022-10-10
C++ LeetCode1796字符串中第二大數(shù)字
這篇文章主要為大家介紹了C++ LeetCode1796字符串中第二大數(shù)字示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
VC實(shí)現(xiàn)給窗體的一個(gè)按鈕添加事件的方法
這篇文章主要介紹了VC實(shí)現(xiàn)給窗體的一個(gè)按鈕添加事件的方法,通過三個(gè)簡(jiǎn)單步驟實(shí)現(xiàn)窗體按鈕添加事件,需要的朋友可以參考下2015-05-05
C語言經(jīng)典算法例題求100-999之間的“水仙花數(shù)”
本文的主要內(nèi)容,設(shè)計(jì)一個(gè)程序,找出100-999之間的“水仙花數(shù)”,需要的朋友可以參考下2015-07-07
linux下c語言中隱藏進(jìn)程命令行參數(shù)(例如輸入密碼等高危操作)
啟動(dòng)程序很多時(shí)候用命令行參數(shù)可以很方便,做到簡(jiǎn)化一些配置,但是輸入用戶名密碼等操作,如果通過進(jìn)程查看工具直接看到密碼就太不安全了,這里就為大家分享一下方法2021-01-01
C語言進(jìn)階輸入輸出重定向與fopen函數(shù)使用示例詳解
這篇文章主要為大家介紹了C語言進(jìn)階輸入輸出重定向與fopen函數(shù)的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-02-02

