用C表達面向對象語言的機制2——顛覆你對方法調用的看法!


用C表達面向對象語言的機制2——顛覆你對方法調用的看法!

源代碼在文末。推薦閱讀本文PDF版,格式更好看。

在上一篇《用C表達面向對象語言的機制——C#版》中,我們獲知了如何用C表達面向對象語言的機制,證明了面向對象語言是對面向過程語言的封裝。今天有幸看到《顛覆你對方法調用的看法!》,於是繼續用C來模擬此文中的代碼,看看“顛覆”的背后是什么。

1. 目標

本文展示用C的union來模擬C#的一些代碼的寫法。

2. 用union代替FieldOffset

例如如下的C#代碼。

Manager

 

如果想用C來實現類似的使用方式,應該如何寫呢?

1) 用union代替FieldOffset

用C的union代替FieldOffset等屬性。

FrancisYoungBase

 

FrancisYoungDerived

 

FrancisYoungManager


就是說,union實現了將父類和子類指針都指向父類的實例的功能。

2) 使用Manager類

C#版的Manager,其典型的使用方式如下。

Manager m = new Manager();
m.derived.Print();// In Derived

對應的C代碼是什么樣的?

FrancisYoungManager * m = NewFrancisYoungManager();
Print4FrancisYoungDerived(m->obj.pDerived);/* In Derived */

與C#版的使用方法異曲同工。
從C版代碼可以看到,編譯器根據pDerived的類型,選擇了調用pDerived的類型中的方法。觀察對C#轉換為C的代碼,可以發現,本質上同名的Print方法,對編譯器而言的代號是不同的,所以編譯器根據pDerived的類型,可以立即確定調用哪個方法。

3. 變為虛函數之后

下面展示將上文中的函數變為虛函數后的處理。

C#代碼如下。

FrancisYoungManagerVirtual

 

 

3) 用函數指針代替虛函數

仍然用上一篇文章的方法,用函數指針來實現虛函數的功能。

FrancisYoungBaseVirtual

 

FrancisYoungDerivedVirtual

 

FrancisYoungManagerVirtual

 

4) 使用ManagerVirtual類

C#代碼的調用方式如下。

ManagerVirtual m = new ManagerVirtual();
m.derived.Print();// In Base

對應的C代碼如下。

FrancisYoungManagerVirtual * m = NewFrancisYoungManagerVirtual();
FrancisYoungBaseVirtual * pBase = (FrancisYoungBaseVirtual*)Convert2Type(m->obj.pDerived->metaInfo, FrancisYoungBaseVirtualTypeId);
pBase->pPrint4FrancisYoungBaseVirtual(pBase);

仍然與之神似。

我們知道,虛方法在C代碼中,變成了一個函數指針。根據上一篇文章的分析,我們在這里創建的是父類的對象,所以Print的函數指針指向的是父類的Print方法,即C版代碼中的Print4FrancisYoungBaseVirtual方法。所以derived調用的只能是父類的Print4FrancisYoungBaseVirtual方法。

4. 結論

對《顛覆你對方法調用的看法!》的分析結果和原作者是一樣的,這也印證了我們上一篇文章的結論的正確性。

感想

上一篇文章我提到,為什么要把C封裝為面向對象語言?面向對象語言是如何從無到有的?最開始的那個人是怎么設計出這樣一套機制的?他之前沒有面向對象的任何概念,他的思路是什么?

通過本文的分析,我的感覺是,面向對象語言的創始人一定是在大量的編寫面向過程語言代碼的時候,逐漸感受到了現實世界和程序語言的嚴重脫節,也發現了兩者之間可能靠近一些的途徑。一個函數寫出來,如果幾乎不可能被其他人用在其他地方,那應該把它隱藏起來,這就是封裝的思想。

而繼承的思想是如何產生的,我還是不得而知。

源代碼在這里


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM