C語言中的物件導向-C語言中的物件導向思想

來源:互聯網
上載者:User

經常聽見別人說物件導向的程式設計,以前在學校上課的時候,也有開物件導向程式設計這門課。可是不幸的是,這些都是以C++,甚至VC++為基礎的。而更加不幸的是,多年以來我一直是一個C的使用者。在學校的時候,我主要做的是硬體上的驅動層,和底層功能層。在工作以後,又做的是手機上的軟體開發,所有這些都是和C離不開的。雖然我不得不說,C++是一門很好的語言,但是它的編譯速度,代碼效率,編譯後的代碼大小都限制了它在嵌入式上的應用。(但現在的嵌入式CPU越來越快,記憶體容量變大。我覺得用C++也應該沒有什麼問題。這使我覺得似乎是嵌入式編譯器的限制。雖然菲利普和TI好像都有C++的編譯器,但是似乎沒人用這個。難道是太貴了? 但不管怎麼說,嵌入式應用中,C語言的普遍使用是肯定的)

那麼在面向過程的時代產生的C語言能否使用物件導向的思想呢?我認為是肯定可以的,C++不過是在語言層級上加入了對對象的支援,同時提供了豐富的物件程式庫。而在C語言下,我們只好自力更生了。

一、           物件導向思想的目的是架構化,手段是抽象

相信很多人都明白物件導向講了什麼:類,抽象類別,繼承,多態。但是是什麼原因促使這些概念的產生呢?

打個比方說:你去買顯示器,然而顯示器的品牌樣式是多種多樣的,你在買的過程中發生的事情也是不可預測的。對於這樣的事情,我們在程式語言中如何去描述呢。物件導向的思想就是為瞭解決這樣的問題。編寫一個程式(甚至說是一個工程),從無到用是困難的,從有到豐富是更加困難的。物件導向將程式的各個行為化為對象,而又用抽象的辦法將這些對象歸類(抽象),從而將錯綜複雜的事情簡化為幾個主要的有機組合(架構化)。

其實我們的身邊很多東西都是這樣組成的:比如說電腦:電腦是由主板,CPU加上各種卡組成的。這就是一個架構化。而忽略不同的CPU,不同的主板,不同的音效卡,網卡,顯卡的區別,這就是抽象。再比如說現在的教育網:是由主核心節點:清華,北大,北郵等幾個,然後是各個子節點,依次組成了整個教育網網路。

所以我覺得物件導向的編程思想就是:一個大型工程是分階層的,每層又由抽象的結構串連為整體(架構化),各個抽象結構之間是彼此獨立的,可以獨立進化(繼承,多態)。層次之間,結構之間各有統一的通訊方式(通常是訊息,事件機制)。

二、           以前C語言編程中常用的“物件導向”方法

其實C語言誕生以來,人們就想了很多辦法來體現“物件導向”的思想。下面就來說說我所知道的方法。先說一些大家熟悉的東東,慢慢再講詭異的。呵呵

 

1.  宏定義:
   有的人不禁要問,宏定義怎麼扯到這裡來了,我們可以先看一個簡單的例子:
#define MacroFunction  Afunction
   然後在程式裡面你調用了大量的AFunction,但是有一天,你突然發現你要用BFunction了,(不過AFunction又不能不要,很有可能你以後還要調用),這個時候,你就可以#define MacroFunction  Bfunction來達到這樣的目的。
   當然,不得不說這樣的辦法是too simple,sometime naïve的,因為一個很滑稽的問題是如果我一般要改為BFunction,一半不變怎麼辦? 那就只好尋找替換了。

 

2.  靜態入口函數,保證函數名相同,利用標誌位調用子函數:
   這樣的典型應用很多,比如說網卡驅動裡面有一個入口函數Nilan(int FunctionCode,Para*)。具體的參數是什麼記不清楚了。不過NiLan的主體是這樣的:
Long Nilan(int FunctionCode,Para*){

Switch(FunctionCode){

       Case SendPacket:         send(….)

       Case ReceivePacket:      receive(…)

       …..

}

寫到這裡大家明白什麼意思了吧。保證相同的函數名就是說:網卡驅動是和pNA+協議棧互連的,那麼如何保證pNA+協議棧和不同的驅動都相容呢,一個簡單的辦法就是僅僅使用一個入口函數。通過改變如果函數的參數值,來調用內部的各個函數。這樣的做法是可以進化的:如果以後想調用新的函數,增加相應的函數參數值就好了。如果我們將網卡驅動和pNA+協議棧看作兩個層的話,我們可以發現:

層與層之間的互串連口是很小的(這裡是一個入口函數),一般是採用名字解析的辦法而不是具體的函數調用(利用FunctionCode調用函數,Nilan僅僅實現名字解析的功能)――!介面限制和名字解析

介面限制:層與層之間僅僅知道有限的函數

名字解析:層與層之間建立共同的名字與函數的對應關係,之間利用名字調用功能。

3.CALLBACK函數。

我覺得這是C語言的一個創舉,雖然它很簡單,就象如何把雞蛋豎起來一樣,但是你如果沒想到的話,嘿嘿。如果說靜態入口函數實現了一個可管理的宏觀的話,CallBack就是實現了一個可進化的微觀:它使得一個函數可以在不重新編譯的情況下實現功能的添加!但是在最最早期的時候,也有蠻多人持反對態度,因為它用了函數指標。函數指標雖然靈活,但是由於它要訪問記憶體兩次才可以調用到函數,第一次訪問函數指標,第二次才是真正的函數調用。它的效率是不如普通函數的。但是在一個不太苛刻的環境下,函數調用本身就不怎麼耗時,函數指標的效能又不是特別糟糕,使用函數指標其實是一個最好的選擇。但是函數指標除了效能,最麻煩的地方就是會導致程式的“支離破碎”。試想:在程式中,你讀到一個函數指標的時候,如果你愣是不知道這個函數指標指向的是哪個函數,那個感覺真的很糟糕。(可以看後面的文章,要使用先進的程式架構,避免這樣的情況)

三、           Event和Message

看了上面的描述,相信大家多少有些明白為什麼要使用Event和Message了。具體的函數調用會帶來很多的問題(雖然從效率上講,這樣做是很好的)。為了提高程式的靈活性,Event和Message的辦法產生了。用名字解析的辦法代替通常的函數調用,這樣,如果雙方對這樣的解析是一致的話,就可以達到一個統一。不過Event和Message的作用還不僅僅是如此。

Event和Message還有建立處理序間通訊的功能。進程將自己的訊息發給“控制中心”(簡單的就是一個訊息佇列,和一個while迴圈不斷的取訊息佇列的內容並執行),控製程序得到訊息,分發給相應的進程,這樣其他進程就可以得到這個訊息並進行響應。

Event和Message是很靈活的,因為你可以隨時添加或者關閉一個進程,(僅僅需要添加分發訊息的列表就可以了)Event和Message從程式實現上將我覺得是一樣的,只不過概念不同。Event多用於指一個動作,比如硬體發生了什麼事情,需要調用一個什麼函數等等。Message多用於指一個指示,比如什麼程式發生了什麼操作命令等等。

四、           小結

其實編程式和寫文章一樣,都是先有一個提綱,然後慢慢的豐富。先抽象化得到程式的骨架,然後再考慮各個方面的其他內容:程式極端的時候會發生什麼問題?程式的這個地方的功能現在還不完善,以後再完善會有什麼問題?程式是不是可以擴充的?

本系列文章是我這些階段的一些心得,目的是拋磚引玉,希望能和大家交流,得到更多的知識。Liyuming1978@163.com (這個信箱以前發了一個文章 C最佳化之路,現在都快成垃圾信箱了,呵呵,網路的力量真是強大呀)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.