OOC的由來
C語言是一種跨平台的,支持硬體互動的底層電腦程式設計語言。C語言具有效率高、兼容性好等多種特點。但是C語言本身不具備面向對象的特性,如果需要實現的是一個超大型的系統,直接使用面向過程的思想,將導致得到一個很大的C檔案,這樣的實現不利於維護。
那么直接使用C++語言是否可行呢?C++是C的超集,繼承了幾乎所有的C語言特性,理論上C語言能夠實現的程式C++都能夠實現,同時還能夠具有面向對象的特性。因此如果在作業系統對於庫函式的支持很完善的情況下,當然是最好使用C++。但是在Linux平台下進行交叉編譯的時候,引用和被引的庫大多都是C庫。如果只是實現一個C++應用程式是沒有問題的,只需在引用C的時候添加extern "C"即可。但是如果實現的是一個C++庫,則它就只能夠被其他C++應用程式引用,而在被C應用程式引用的時候,將需要對整個庫重新編譯。
一種很好的解決方案就是OOC編程思想。OOC是在C程式中借用C++面向對象編程思想,簡而言之就是用C模擬C++,將封裝、繼承和多態使用C進行實現。OOC既保持了C語言的所有優點,又具有C++的面向對象特性。OOC和簡單的C++語法上大致一一對應,因此可以實現較快的相互轉換。需提及的是,OOC的實現並沒有形成一個通用的計算機程式語言標準,因此本文所述的只是其中一種方法,事實上許多程式設計者們都實現了一套自己的OOC,參見。程式設計者們可以發揮想像力,實現符合自己編程風格的OOC。
封裝
我們現在先來看一下怎樣用C編寫一個模擬的類(Class)。C提供了結構體(struct),我們可以用C的struct來模擬C++的Class。
現在先來實現類的封裝:對象具有一定的記憶體空間,我們可以向其中放入和取出信息。首先定義模擬類
接著在同名.c檔案中實現方法
這樣類就實現完成了。我們這種方法是用
用來模擬C++的函式前綴"SimClass::",這樣就避免了多個類的同名函式造成的重定義。然後再將結構體
作為第一個參數傳入成員函式,這樣在成員函式中就能夠訪問類的成員變數了。
封裝後就能夠很容易地復用了:例如
這樣看起來main函式就清楚多了。其實OCC模擬類的實現方法有多種多樣,還有一種方法是在struct中設定函式指針(function pointer),然後將函式指針指向對應方法。這種實現的代碼更加具有可讀性,但是實現本身較為複雜。
繼承
接下來使用C實現繼承。為簡單起見我們這次用幾個簡單一點的模擬類來說明。為簡化起見類操作將不涉及開闢和釋放空間,從而可以捨棄構造和析構函式。將精力集中在繼承。
這是模擬類Base
這是模擬類Derive
派生類必須有一個繼承類的成員,用於表示它是繼承自它的。這裡DERIVE是一個空宏,用於表示這個成員是一個繼承的基類。這樣寫是便於理解。
他們的.c檔案實現如下
這樣在主函式中就能很方便地調用繼承類了。
可見,當我們只需要用到繼承類Derive時,甚至都可以不必知道Base類的存在和它們的繼承關係,直接就可以用Derive類,這樣是很便於軟體分層開發的。
多態
C也可以實現多態。不過這種多態和C++中的多態有所不同,此處不允許同名的成員函式。但是,我們仍然可以實現一種模擬的多態。
什麼是多態?簡單地說就是主函式訪問繼承類Derive的成員函式時,如果Derive類存在此函式,就直接調用它;而如果Derive類沒有,但是Base類有此函式,則間接調用父類的那個函式。
我們不妨任然拿上一節說的Base類和Derive類來用。事實上我們要做的就是改一下main函式,要也像上一節一樣,在其中增加一個繼承描述表。由於需要支持的是可以有多個對象的類,所以這個繼承描述表必須是動態繼承描述表,就是說帶一個變數:
也可以定義多個Derive對象。分析一下這個架構,可以知道同一個類中,每個對象都擁有自己的一套成員變數,所以它們在進行繼承和多態的時候,是相互不會影響的。另外,也可見同類的對象都共同使用一套成員函式,所以原始碼的復用程度都非常高。這樣就實現了OOC。
需要注意的是,本文所述的的只是實現OOC的一種方法,只實現了簡單的封裝、繼承和多態,遠沒有實現C++語言提供的所有功能。但是使用OOC的編程思想,開發出的C語言源程式具有較高的源碼復用率,面向對象的思想也使模組接口更易於調用。