C++对象的内存分析(5)
前言
??? 前面4節我們已經完成了對4種C++對象布局的分析,本文試圖覆蓋更多的,常見的C++面向對象的概念。所以,最后2節將繼續闡述2個主題:接口和抽象類以及構造函數、虛構函數和虛析構函數。
接口
??? 這里我準備只主要闡述接口,而不談一般的抽象類。因為在C++中,是沒有“接口”這種類型的,所有的接口事實上是定義為純抽象類。所謂純抽象類,就是沒有 成員變量,沒有實現了的函數,只有純虛函數的抽象類。我相信,理解了接口這種特殊的抽象類,再去理解一般的抽象類是很容易的。
??? 來看一個例子,我們有接口IAnimal來表示一般的動物行為,代碼如下:
| class IAnimal { public: ????virtual void Eat()=0; ????virtual void Move()=0; ????virtual void Sleep()=0; }; |
??? 這個接口在內存中的布局可以看作下圖中的樣子:
?
??? 接口在內存中的布局可以看作一個虛函數指針指向一個虛函數表,虛函數表中的所有元素指向的地址為0,因為所有純虛函數都沒有被實現。
??? 上面的描述只是為了大家理解方便,事實上這種說法是很不準確的。因為,一個接口是絕對不能被構造的,這一點很重要。接口中的純虛函數都沒有被實現,如果允許構造他們,那么在調用這些方法的時候,將造成非法訪問異常。
??? 我們的問題來了,既然接口不允許被構造,那么我們為什么經常看到各種接口類型的對象呢。很簡單,這些接口類型的對象都是由從該接口繼承的子類對象通過類型 轉換而來的。在子類中,我們需要實現接口的所有方法,否則,該子類仍是一個抽象類。下圖中,我們描述了繼承了IAnimal接口的Horse類的內存結構 圖,這個類還繼承了IVehicle接口:
??? 關于Horse類如果進行指針調整,怎么轉換為IAnimal接口類型,并實現多態特性的,我們在前面的章節中不止一次涉及到,即使是接口,也沒有什么不同,我們這里不打算再重復。
??? 下面,我們要談的是,為什么我們要使用接口呢? 由于本文主要研究的是對象的內存布局,所以,關于這個涉及設計模式的主題,我只準備簡單的講述,這個主題太大了,因此我只希望下面的描述能給你一些關于接 口應用場景的靈感。我們經常聽到關于接口的描述是“只要實現了某某接口,對象就能實現某某功能/流程”,或者“就能被某某方法/模塊調用來實現某某功能 /流程”。 我們來看下面的代碼:
| void AnimalHappyDay(IAnimal* animal) { ????animal->Eat(); ????animal->Move(); ????animal->Sleep(); } |
?? 類似的,我們要說,任何類只要實現了IAnimal接口,AnimalHappyDay函數就可以調用該類的對象,來實現動物快樂的一天!我們不用關心這 個類是貓,狗還是獨角獸,不用關心它是否還實現了其他的接口,不用關心它是直接實現IAnimal接口的,還是間接的。他們只有一個共同點,就是實現了 IAnimal接口。那么,它就可以被AnimalHappyDay函數調用,Eat,Move,Sleep,來實現動物快樂的一天這個功能。
??? 一個接口,應該是最小粒度的。所謂最小粒度,首先,它沒有任何的實現,只是用來描述一種標準的調用規范,完全由子類去實現它。其次,它只包含實現流程需要 的最小的方法集合,比如,我們在IAnimal接口中不應該加入Grow方法,因為AnimalHappyDay流程不需要該方法,如果我們加入Grow 方法,所有繼承IAnimal的類就不得不去實現它。應該把Grow方法放在其他接口中,比如ILIfe接口,這個接口中或許定義了Both,Dead方 法,用來實現動物的生命周期,類作者可以選擇是否要去實現該接口。
?
轉載于:https://blog.51cto.com/sensen/740283
總結
以上是生活随笔為你收集整理的C++对象的内存分析(5)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 记一次小的51CTO聚会
- 下一篇: 后台CS代码中创建四种常用的SL动画效果