• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 74, 文章 - 0, 評論 - 26, 引用 - 0
            數(shù)據(jù)加載中……

            C語言中的面向?qū)ο?/a>

            一 、面向?qū)ο笏枷?br />


            一、 面向?qū)ο笏枷氲哪康氖强蚣芑侄问浅橄?br />
            相信很多人都明白面向?qū)ο笾v了什么:類,抽象類,繼承,多態(tài)。但是是什么原因促使這些概念的產(chǎn)生呢?

            打個比方說:你去買顯示器,然而顯示器的品牌樣式是多種多樣的,你在買的過程中發(fā)生的事情也是不可預測的。對于這樣的事情,我們在程序語言中如何去描述呢。面向?qū)ο蟮乃枷刖褪菫榱私鉀Q這樣的問題。編寫一個程序(甚至說是一個工程),從無到用是困難的,從有到豐富是更加困難的。面向?qū)ο髮⒊绦虻母鱾€行為化為對象,而又用抽象的辦法將這些對象歸類(抽象),從而將錯綜復雜的事情簡化為幾個主要的有機組合(框架化)。

            其實我們的身邊很多東西都是這樣組成的:比如說電腦:電腦是由主板,CPU加上各種卡組成的。這就是一個框架化。而忽略不同的CPU,不同的主板,不同的聲卡,網(wǎng)卡,顯卡的區(qū)別,這就是抽象。再比如說現(xiàn)在的教育網(wǎng):是由主核心節(jié)點:清華,北大,北郵等幾個,然后是各個子節(jié)點,依次組成了整個教育網(wǎng)網(wǎng)絡。

            所以我覺得面向?qū)ο蟮木幊趟枷刖褪牵阂粋€大型工程是分層次結(jié)構(gòu)的,每層又由抽象的結(jié)構(gòu)連接為整體(框架化),各個抽象結(jié)構(gòu)之間是彼此獨立的,可以獨立進化(繼承,多態(tài))。層次之間,結(jié)構(gòu)之間各有統(tǒng)一的通訊方式(通常是消息,事件機制)。

            二、 以前 C 語言編程中常用的“面向?qū)ο蟆狈椒?br />
            其實C語言誕生以來,人們就想了很多辦法來體現(xiàn)“面向?qū)ο蟆钡乃枷搿O旅婢蛠碚f說我所知道的方法。先說一些大家熟悉的東東,慢慢再講詭異的。呵呵

            1. 宏定義:

            有的人不禁要問,宏定義怎么扯到這里來了,我們可以先看一個簡單的例子:

            #define MacroFunction Afunction

            然后在程序里面你調(diào)用了大量的AFunction,但是有一天,你突然發(fā)現(xiàn)你要用BFunction了,(不過AFunction又不能不要,很有可能你以后還要調(diào)用),這個時候,你就可以#define MacroFunction Bfunction來達到這樣的目的。

            當然,不得不說這樣的辦法是too simple,sometime na?ve的,因為一個很滑稽的問題是如果我一般要改為BFunction,一半不變怎么辦? 那就只好查找替換了。

            2. 靜態(tài)的入口函數(shù),保證函數(shù)名相同,利用標志位調(diào)用子函數(shù):

            這樣的典型應用很多,比如說網(wǎng)卡驅(qū)動里面有一個入口函數(shù)Nilan(int FunctionCode,Para*)。具體的參數(shù)是什么記不清楚了。不過NiLan的主體是這樣的:

            Long Nilan(int FunctionCode,Para*){

            Switch(FunctionCode){

            Case SendPacket: send(….)

            Case ReceivePacket: receive(…)

            …..

            }

            寫到這里大家明白什么意思了吧。保證相同的函數(shù)名就是說:網(wǎng)卡驅(qū)動是和pNA+協(xié)議棧互連的,那么如何保證pNA+協(xié)議棧和不同的驅(qū)動都兼容呢,一個簡單的辦法就是僅僅使用一個入口函數(shù)。通過改變?nèi)绻瘮?shù)的參數(shù)值,來調(diào)用內(nèi)部的各個函數(shù)。這樣的做法是可以進化的:如果以后想調(diào)用新的函數(shù),增加相應的函數(shù)參數(shù)值就好了。如果我們將網(wǎng)卡驅(qū)動和pNA+協(xié)議棧看作兩個層的話,我們可以發(fā)現(xiàn):

            層與層之間的互連接口是很小的(這里是一個入口函數(shù)),一般是采用名字解析的辦法而不是具體的函數(shù)調(diào)用(利用FunctionCode調(diào)用函數(shù),Nilan僅僅實現(xiàn)名字解析的功能) ――!接口限制和名字解析

            接口限制:層與層之間僅僅知道有限的函數(shù)

            名字解析:層與層之間建立共同的名字與函數(shù)的對應關系,之間利用名字調(diào)用功能。

            3.CALLBACK函數(shù)。

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

            三、 Event 和 Message

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

            Event和Message還有建立進程間通信的功能。進程將自己的消息發(fā)給“控制中心”(簡單的就是一個消息隊列,和一個while循環(huán)不斷的取消息隊列的內(nèi)容并執(zhí)行),控制程序得到消息,分發(fā)給相應的進程,這樣其他進程就可以得到這個消息并進行響應。

            Event和Message是很靈活的,因為你可以隨時添加或者關閉一個進程,(僅僅需要添加分發(fā)消息的列表就可以了)Event和Message 從程序?qū)崿F(xiàn)上將我覺得是一樣的,只不過概念不同。Event多用于指一個動作,比如硬件發(fā)生了什么事情,需要調(diào)用一個什么函數(shù)等等。Message多用于指一個指示,比如什么程序發(fā)生了什么操作命令等等。

            四、 小結(jié)

            其實編程序和寫文章一樣,都是先有一個提綱,然后慢慢的豐富。先抽象化得到程序的骨架,然后再考慮各個方面的其他內(nèi)容:程序極端的時候會發(fā)生什么問題?程序的這個地方的功能現(xiàn)在還不完善,以后再完善會有什么問題?程序是不是可以擴展的?

            二、類模擬的性能分析

            ? 類模擬中使用了大量的函數(shù)指針,結(jié)構(gòu)體等等,有必須對此進行性能分析,以便觀察這樣的結(jié)構(gòu)對程序的整體性能有什么程度的影響。

              1.函數(shù)調(diào)用的開銷

            #define COUNTER XX
            void testfunc()
            {
            ? int i,k=0;
            ? for(i=0;i<YY;i++)
            }

              在測試程序里面,我們使用的是一個測試函數(shù),函數(shù)體內(nèi)部可以通過改變YY的值來改變函數(shù)的耗時。測試對比是 循環(huán)調(diào)用XX次函數(shù),和循環(huán)XX次函數(shù)內(nèi)部的YY循環(huán)。

              結(jié)果發(fā)現(xiàn),在YY足夠小,X足夠大的情況下,函數(shù)調(diào)用耗時成為了主要原因。所以當一個“簡單”功能需要“反復”調(diào)用的時候,將它編寫為函數(shù)將會對性能有影響。這個時候可以使用宏,或者inline關鍵字。

              但是,實際上我設置XX=10000000(1千萬)的時候,才出現(xiàn)ms級別的耗時,對于非實時操作(UI等等),即使是很慢的cpu(嵌入式10M級別的),也只會在XX=10萬的時候出現(xiàn)短暫的函數(shù)調(diào)用耗時,所以實際上這個是可以忽略的。

              2.普通函數(shù)調(diào)用和函數(shù)指針調(diào)用的開銷

            void (*tf)();
            tf=testfunc;

              測試程序修改為一個使用函數(shù)調(diào)用,一個使用函數(shù)指針調(diào)用。測試發(fā)現(xiàn)對時間基本沒有什么影響。(在第一次編寫的時候,發(fā)現(xiàn)在函數(shù)調(diào)用出現(xiàn)耗時的情況下(XX=1億),函數(shù)指針的調(diào)用要慢(release版本),調(diào)用耗時350:500。后來才發(fā)現(xiàn)這個影響是由于將變量申請為全局的原因,全局變量的訪問要比局部變量慢很多)。

              3.函數(shù)指針和指針結(jié)構(gòu)訪問的開銷

            struct a {
            ? void (*tf)();
            }

              測試程序修改為使用結(jié)構(gòu)的函數(shù)指針,測試發(fā)現(xiàn)對時間基本沒有什么影響。其實使用結(jié)構(gòu)并不會產(chǎn)生影響,因為結(jié)構(gòu)的訪問是固定偏移量的。所以結(jié)構(gòu)變量的訪問和普通變量的訪問對于機器碼來說是一樣的。

              測試結(jié)論:使用類模擬的辦法對性能不會產(chǎn)生太大的影響。

            三、C語言的多態(tài)實現(xiàn)

              相信很多人都看過設計模式方面的書,大家有什么體會呢?Bridge,Proxy,F(xiàn)actory這些設計模式都是基于抽象類的。使用抽象對象是這里的一個核心。
            ? ?
              其實我覺得框架化編程的一個核心問題是抽象,用抽象的對象構(gòu)建程序的主體框架,這是面向?qū)ο缶幊痰钠毡樗枷搿S贸橄髽?gòu)建骨架,再加上多態(tài)就形成了一個完整的程序。由于C++語言本身實現(xiàn)了繼承和多態(tài),使用這樣的編程理念(理念啥意思?跟個風,嘿嘿)在C++中是十分普遍的現(xiàn)象,可以說Virtual(多態(tài))是VC的靈魂。

              但是,使用C語言的我們都快把這個多態(tài)忘光光了。我常聽見前輩說,類?多態(tài)?我們用的是C,把這些忘了吧。很不幸的是,我是一個固執(zhí)的人。這么好的東西,為啥不用呢。很高興的,在最近的一些純C代碼中,我看見了C中的多態(tài)!下面且聽我慢慢道來。

              1. VC中的Interface是什么

              Interface:中文解釋是接口,其實它表示的是一個純虛類。不過我所要說的是,在VC中的Interface其實就是struct,查找Interface的定義,你可以發(fā)現(xiàn)有這樣的宏定義:

            ? ? #Ifndef Interface
            ? ? #define Interface struct
            ? ? #endif

              而且,實際上在VC中,如果一個類有Virtual的函數(shù),則類里面會有vtable,它實際上是一個虛函數(shù)列表。實際上C++是從C發(fā)展而來的,它不過是在語言級別上支持了很多新功能,在C語言中,我們也可以使用這樣的功能,前提是我們不得不自己實現(xiàn)。

              2.C中如何實現(xiàn)純虛類(我稱它為純虛結(jié)構(gòu))

              比較前面,相信大家已經(jīng)豁然開朗了。使用struct組合函數(shù)指針就可以實現(xiàn)純虛類。

              例子:

            ? typedef struct {
            ? ? void (*Foo1)();
            ? ? char (*Foo2)();
            ? ? char* (*Foo3)(char* st);
            ? }
            ? MyVirtualInterface;
            ? ?
              這樣假設我們在主體框架中要使用橋模式。(我們的主類是DoMyAct,接口具體實現(xiàn)類是Act1,Act2)下面我將依次介紹這些“類”。(C中的“類”在前面有說明,這里換了一個,是使用早期的數(shù)組的辦法)

              主類DoMyAct: 主類中含有MyVirtualInterface* m_pInterface; 主類有下函數(shù):

            ? DoMyAct_SetInterface(MyVirtualInterface* pInterface)
            ? {
            ? ? m_pInterface= pInterface;
            ? }
            ? DoMyAct_Do()
            ? {
            ? ? if(m_pInterface==NULL) return;
            ? ? m_pInterface->Foo1();
            ? ? c=m_pInterface->Foo2();
            ? }

              子類Act1:實現(xiàn)虛結(jié)構(gòu),含有MyVirtualInterface st[MAX]; 有以下函數(shù):

            ? MyVirtualInterface* Act1_CreatInterface()
            ? {
            ? ? index=FindValid() //對象池或者使用Malloc !應該留在外面申請,實例化
            ? ? if(index==-1) return NULL;
            ? ? St[index].Foo1=Act1_Foo1; // Act1_Foo1要在下面具體實現(xiàn)
            ? ? St[index].Foo2=Act1_Foo2;
            ? ? St[index].Foo3=Act1_Foo3;
            ? ? Return &st [index];
            ? }

              子類Act2同上。

              在main中,假設有一個對象List。List中存貯的是MyVirtualInterface指針,則有:

            ? if( (p= Act1_CreatInterface()) != NULL)
            ? List_AddObject(&List, p); //Add Al

            ? While(p=List_GetObject()){
            ? ? DoMyAct_SetInterface(p);//使用Interface代替了原來大篇幅的Switch Case
            ? ? DoMyAct_Do();//不要理會具體的什么樣的動作,just do it
            ? }

            ? FREE ALL

            四、類模擬和多態(tài),繼承

              在面向?qū)ο蟮恼Z言里面,出現(xiàn)了類的概念。這是編程思想的一種進化。所謂類:是對特定數(shù)據(jù)的特定操作的集合體。所以說類包含了兩個范疇:數(shù)據(jù)和操作。而C語言中的struct僅僅是數(shù)據(jù)的集合。(
            liyuming1978@163.com)

              1.實例:下面先從一個小例子看起

            #ifndef C_Class
            ? ? #define C_Class struct
            #endif

            C_Class A {
            ? ? C_Class A *A_this;
            ? ? void (*Foo)(C_Class A *A_this);
            ? ? int a;
            ? ? int b;
            };

            C_Class B{ ? ? ? ? ? //B繼承了A
            ? ? C_Class B *B_this; //順序很重要
            ? ? void (*Foo)(C_Class B *Bthis); ? ? ? ? //虛函數(shù)
            ? ? int a;
            ? ? int b;

            ? ? int c;
            };


            void B_F2(C_Class B *Bthis)
            {
            ? ? printf("It is B_Fun\n");
            }

            void A_Foo(C_Class A *Athis)
            {
            ? ? printf("It is A.a=%d\n",Athis->a);//或者這里
            // ? exit(1);
            // ? printf("純虛 不允許執(zhí)行\(zhòng)n");//或者這里
            }

            void B_Foo(C_Class B *Bthis)
            {
            ? ? printf("It is B.c=%d\n",Bthis->c);
            }

            void A_Creat(struct A* p)
            {
            ? ? p->Foo=A_Foo;
            ? ? p->a=1;
            ? ? p->b=2;
            ? ? p->A_this=p;
            }


            void B_Creat(struct B* p)
            {
            ? ? p->Foo=B_Foo;
            ? ? p->a=11;
            ? ? p->b=12; ? ?
            ? ? p->c=13;
            ? ? p->B_this=p;
            }


            int main(int argc, char* argv[])
            {
            ? ? C_Class A *ma,a;
            ? ? C_Class B *mb,b;

            ? ? A_Creat(&a);//實例化
            ? ? B_Creat(&b);

            ? ? mb=&b;
            ? ? ma=&a;

            ? ? ma=(C_Class A*)mb;//引入多態(tài)指針
            ? ? printf("%d\n",ma->a);//可惜的就是 函數(shù)變量沒有private
            ? ? ma->Foo(ma);//多態(tài)
            ? ? a.Foo(&a);//不是多態(tài)了
            ? ? B_F2(&b);//成員函數(shù),因為效率問題不使用函數(shù)指針
            ? ? return 0;
            }


              輸出結(jié)果:

            11
            It is B.c=13
            It is A.a=1
            It is B_Fun</P< p>

            posted on 2006-06-26 18:31 井泉 閱讀(336) 評論(1)  編輯 收藏 引用 所屬分類: c軟件工程

            評論

            # re: C語言中的面向?qū)ο?a name="Post">  回復  更多評論   

            列子不錯
            2010-03-09 16:11 | nfl 2010
            欧美久久亚洲精品| 久久99精品国产麻豆蜜芽| 久久亚洲综合色一区二区三区| 亚洲午夜精品久久久久久浪潮| 色狠狠久久综合网| 久久九色综合九色99伊人| 亚洲AV无一区二区三区久久| 国产成人综合久久久久久| 999久久久无码国产精品| 国产美女亚洲精品久久久综合| 国产精品久久久久久久| 久久婷婷五月综合色高清| 亚洲成av人片不卡无码久久| 国内精品久久久久久久久电影网| 久久午夜羞羞影院免费观看| 99精品久久久久久久婷婷| 国产成人精品久久| 亚洲综合久久夜AV | 亚洲国产成人乱码精品女人久久久不卡| 色欲综合久久中文字幕网| 日韩人妻无码精品久久久不卡| 国内精品久久久久影院优| 国内精品久久久久久久97牛牛| 久久99国产精品久久99果冻传媒| 国内精品久久久久伊人av| 狠狠精品干练久久久无码中文字幕| 国产精品久久国产精品99盘 | 国内精品人妻无码久久久影院| 国产精品久久波多野结衣| 色天使久久综合网天天| 99久久精品影院老鸭窝| 伊人久久大香线蕉精品不卡| 亚洲精品乱码久久久久久蜜桃图片| 久久被窝电影亚洲爽爽爽| 中文精品99久久国产| 国产69精品久久久久9999| 国产精品久久久久…| www.久久热.com| 久久久久夜夜夜精品国产| 亚洲狠狠婷婷综合久久蜜芽 | 国内精品久久久久影院老司|