• <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>

            第一桶 從C到C++ 第十碗 老C初論對象模型 小P學(xué)習(xí)基于對象(之一)


                  又是一個陽光明媚的下午,九月的太陽照在人身上暖洋洋的。小P整理完《數(shù)字信號處理》的課件、筆記和作業(yè),長長的伸了一個懶腰。“看來我還要復(fù)習(xí)復(fù)習(xí)《信 號與系統(tǒng)》。”他自言自語的說道。扭頭看看老C,好像剛剛和《數(shù)理統(tǒng)計》斗爭完畢。于是他把轉(zhuǎn)椅轉(zhuǎn)向老C,“呵呵,剛才在做作業(yè)嗎?”
                 “嗯,我剛剛和正態(tài)分布纏斗了一番,最后終于將它打倒在地……”老C開始吹噓。
                 “嘻嘻,”小P竊笑,心想自己不過20分鐘搞定的事情這個家伙居然用了快一個小時,看來還是有些老啊,“我說,上次我們的代碼已經(jīng)到2.0版本了,你說下來要使用C++了,我們就開始這個活動如何?”
                 “……”老C看看表,離吃飯還有快2個小時,于是說道,“你今天不去踢球嗎?好,那么我們就來進行C++的部分。”于是他湊到小P電腦旁邊,又把白板從角落中拉了出來。“你這幾天看了我們寫出的代碼了嗎?”
                 “嗯,花了一些時間看了看,還試著自己重新實現(xiàn)了一下,但是我自己在編寫程序的時候發(fā)現(xiàn)一些問題……”小P應(yīng)道。
                 “哦?說來聽聽?”老C追問。
                 “首先是初始化,如果我們采用function(DATA*)的形式來編程,必不可少需要類似于initXXX(DATA*)的函數(shù)來初始化數(shù)據(jù)的狀態(tài), 但是我經(jīng)常忘記在程序的開頭調(diào)用initXXX()函數(shù)來初始化數(shù)據(jù)的狀態(tài),很容易造成數(shù)據(jù)敗壞。”小P眨眨眼,“還有內(nèi)存清理的問題,比如在使用 linked list的相關(guān)函數(shù)時,如果我忘記在程序最后調(diào)用ListClear()函數(shù),那么就很容易出現(xiàn)內(nèi)存泄漏,就算我調(diào)用了ListClear()函數(shù),如果 在下次使用這個linked list時,忘記調(diào)用了ListInitList()函數(shù),也會造成數(shù)據(jù)敗壞而沒有任何提示……”
                 “是啊是啊,這個是經(jīng)常遇到的問題,還有嗎?”老C追問。
                 “嗯,因為經(jīng)常要使用DATA的指針類型,開始時有些不習(xí)慣……”小P想了想。
                 “呵呵,你說的這些都是事實,而且在很長一段時間都困擾者開發(fā)人員,因此才有了C++的發(fā)明啊。”老C說道,“人們覺得用這種方式開發(fā)程序是很好的事情, 使得代碼模塊更容易構(gòu)造,但是由于C語言沒有在語言層面對此種方法進行直接支持,所以在采用以數(shù)據(jù)為中心的思想進行開發(fā)時,總會有這樣或者那樣的不方便。 于是人們想,可以在C語言中加入一些特性,使得基于對象的開發(fā)更方便一些,這樣才有了C++語言的前身……”
                 “是嗎?那么是怎么一會事情呢?”小P問。
                 “哦,我們來舉個例子。”說著老C在白板上勾畫了兩段代碼。

            C:
            typedef struct tagDATA
            {
                int a_;
            }DATA;

            void func(DATA* data)
            {
                data->a_ = 1;
            }

            int main()
            {
                DATA data;
               
                func(&data);

                return 0;
            }

            C++:
            class DATA
            {
            public:
                void func(){ a_ = 1; }
            private:
                int a_;
            }

            int main()
            {
                DATA data;

                data.func();
            }

                 “看看,兩段代碼雖然語法差別很大,但是實現(xiàn)的功能是一樣的,都是對數(shù)據(jù)DATA中的a_變量賦值1。”老C解釋到,“其實這里的C++代碼可以翻譯成C代碼的。”他又在白板的空白處寫下如下代碼。

            C++被翻譯為C后:
            class DATA
            {
            public:
                void func(DATA* this) { this->a_ = 1; } 
            private:
                int a_;
            }

            int main()
            {
                DATA data;
               
                // data.func();
                DATA::func(&data);
            }

                 “不過這些都是編譯器私下里進行的活動,你就認為上面的代碼是編譯過程的中間代碼就行了——不過最初的C++代碼的確被編譯為C代碼后再編譯的。”老C解釋,“同時這也解釋了this關(guān)鍵字在C++中是什么意思。”老C接著說道。
                 “哦?這樣有什么好處呢?”小P問道。
                 “最大的好處是在語言層面對基于對象的編程方法給予了更多的支持,這樣在開發(fā)的時候開發(fā)人員的智力負擔(dān)會小很多……”老C停了一下,加重了語氣,“我們做 事情的目的是簡化問題,任何新工具和新方法被發(fā)明的目的都是為了使問題看起來更簡單一些,而不是使問題看起來更復(fù)雜。”老C想了想,“如果你了解了某種語 言特性所針對的需求,你就可以更準(zhǔn)確的使用這種語言特性而不會出現(xiàn)誤解,同時也會說,啊,這樣多好,不得不如此。”
                 “是嗎?”小P有被噴暈了。
                 “是啊是啊,比如我們使用struct封裝數(shù)據(jù)的屬性,并將此數(shù)據(jù)與對它的操作放在同一個編譯單元中,將內(nèi)部的操作聲明為static函數(shù)……一切的一切 都是業(yè)內(nèi)流行的做法而已,語言并沒有強制你這樣做,而且也沒有提供給你更好的工具以支持這種編碼風(fēng)格。但在C++語言下,語言可以給我們提供工具使得我們 可以更方便的實現(xiàn)自己的編程思想——雖然在C下面也可以實現(xiàn),但沒有在C++下方便啊。”老C忍不住喝了一大口水,“比如我們的數(shù)據(jù),可以放在class 的private部分;而對外的接口,可以放在public部分供其它模塊調(diào)用;模塊內(nèi)部的操作可以放在private部分加以隱藏;而且還提供構(gòu)造和析 構(gòu)函數(shù)用于我們方便的初始化數(shù)據(jù)和銷毀數(shù)據(jù)。”
                 “嗯,這樣說來語言的確提供了便利性……”小P回答,“我以前覺得C++難以學(xué)習(xí),可能是沒有了解各種語言特性所應(yīng)對的實際需求吧。”
                 “是啊是啊,”老C感嘆,“我們就對比對比C語言基于對象風(fēng)格的編程和C++語言的對象模型,一探語言特性的究竟。”說著他又在白板上修改了一下C代碼。

            C:
            typedef struct tagDATA
            {
                int a_;
                int b_;   
            }DATA;

            void DataFunc(DATA* data)
            {
                data->a_ = 1;
            }

            int main()
            {
                DATA data;
               
                DataFunc(&data);

                return 0;
            }

                 “當(dāng)我們寫下這樣的main()代碼的時候,到底會發(fā)生什么事情呢?”老C問,看到小P一副囧囧的樣子,決定自己回答這個問題,“首先我們在使用 typedef的時候,一些類型信息會被記錄到內(nèi)存中;當(dāng)我們寫下DataFunc()函數(shù)時,這個函數(shù)出現(xiàn)在我們代碼的全局中,也就是說它是全局可見 的;當(dāng)我們寫下Data data語句的時候,一塊新的內(nèi)存在棧上被分配,其內(nèi)部的信息根據(jù)以前的記錄,被分配為兩個int類型,其值是隨機的。”說著他在白板上畫了幾個框框。

                 “看,為了避免在項目中出現(xiàn)同名函數(shù)的問題,我們不得不在對數(shù)據(jù)DATA的操作Func前加上前綴Data以表征DataFunc()函數(shù)作用于DATA 數(shù)據(jù),這樣可以在很大程度上避免命名沖突。”老C解釋道,“經(jīng)過DataFunc(&data)函數(shù)調(diào)用,內(nèi)存中&data指針?biāo)赶虻? 地址開始,a_的內(nèi)容就變?yōu)?了。”
                 “那么在C++中的情況呢?”小P問。
                 “與在C中是一模一樣的。”老C肯定的回答,“不要被語法欺騙了眼睛,在實質(zhì)上它們兩者是完全相同的。”說著他修改了C++部分的代碼。

            C++:
            class Data
            {
            public:
                void func();
            private:
                int a_;
                int b_;
            }

            void Data::func()
            {
                a_ = 1;
            }

            int main()
            {
                Data data;

                data.func();

                return 0;
            }

                 “雖然我們將func()函數(shù)聲明在class Data內(nèi)部,但是這個與Data所分配的內(nèi)存大小完全無關(guān)。在這只是表現(xiàn)出func()名字空間的關(guān)系,Data類型占內(nèi)存的大小還是根據(jù)其內(nèi)部數(shù)據(jù)所 占的內(nèi)存大小決定的。”老C解釋道,“我們來用C語言翻譯一下C++代碼的意思。”

            C++被翻譯為C后:
            struct Data
            {
            private:
                int a_;
                int b_;
            }

            void Data::func(Data* this);

            void Data::func(Data* this)
            {
                this->a_ = 1;
            }

            int main()
            {
                Data data;
               
                Data::func(&data);

                return 0;
            }

                 “看,其實意思是一樣的,不過就是C++的語法更特殊一些而已。”老C道,“由于func()函數(shù)被聲明在Data數(shù)據(jù)內(nèi)部,因此其名字空間就在Data內(nèi)部,這樣函數(shù)就不會和其它模塊的函數(shù)發(fā)生命名沖突。”老C說著又畫了一個框框。


                 “看吧,其實沒有什么不同,而且我們還省去了使用命名規(guī)范避免函數(shù)命名沖突的麻煩……”老C道,“一般業(yè)內(nèi)的習(xí)俗發(fā)展到一定程度也會變?yōu)檎Z言特性的,這在很多語言發(fā)展的歷史上都可以證明。”
                 “那么public和private呢?”小P問。
                 “public與private只能說明某操作或者數(shù)據(jù)屬性在名字空間內(nèi)部的可見性,而不影響其在內(nèi)存和名字空間的位置。”老C解釋,“以后我們解釋可見 性的時候會再次提及的。現(xiàn)在你只要記住凡是public域的函數(shù)或者數(shù)據(jù),均可以通過.運算符和->運算符操作,而在private域內(nèi)的,只能由 此命名空間內(nèi)的函數(shù)操作。ok?”
                 “好的,我記住了。”小P回答。
                 “好了,了解了C++中基于對象部分的特性,我們再使用C++改寫我們的apple game。”老C道。他刪除了項目中除mydebug.h外的所有文件,然后又新建了 main.cpp,applegame.h,applegame.cpp和childlist.h文件,并將這些文件添加到工程中。
                 “同樣,根據(jù)我們的開發(fā)方法,我們先寫一個大概的框架出來。先在main.cpp中添這樣的代碼。”老C一邊說,一邊敲下如下代碼。

            main.cpp:

            #include "applegame.h"

            int main()
            {
                AppleGame theGame;

                theGame.play();

                return 0;
            }

            ------------------------------------------------------(樸實的分割線)

                 “看來我們需要AppleGame有一個play()的接口。”老C一邊自言自語,一邊寫下applegame.h文件的內(nèi)容。

            applegame.h:

            #if !defined(APPLE_GAME_H_)
            #define APPLE_GAME_H_

            #include "childlist.h"

            class AppleGame
            {
            public:
                void play();

            private:
                bool isGameOver() const;
                void doPlay();
                int lastChildSeatNum() const;

            private:
                ChildList childList_;
            };

            #endif // APPLE_GAME_H_

            ------------------------------------------------------(樸實的分割線)


                 “嗯,看來我們還需要一個ChildList模塊。”他又在childlist.h中寫下如下內(nèi)容。

            childlist.h:

            #if !defined(CHILD_LIST_H_)
            #define CHILD_LIST_H_

            class ChildList
            {
            public:
            };

            #endif // CHILD_LIST_H_

            ------------------------------------------------------(樸實的分割線)

                 “嗯,下來我們來實現(xiàn)apple game中的具體內(nèi)容。”老C自言自語道。

            applegame.cpp:

            #include "applegame.h"
            #include "mydebug.h"

            #include <iostream>

            //////////////////////////////////////////////////////////////////////////
            // Public

            void AppleGame::play()
            {
                using namespace std;

                MY_DEBUG("Start playing game...\n");

                while (!isGameOver())
                {
                    doPlay();
                }

                cout << "The last child's seat number is: " << lastChildSeatNum() << endl;
            }


            //////////////////////////////////////////////////////////////////////////
            // Private

            bool AppleGame::isGameOver() const
            {
                static int i = -1;

                return 1 == i++;
            }

            void AppleGame::doPlay()
            {
                MY_DEBUG("Playing game.\n");
            }

            int AppleGame::lastChildSeatNum() const
            {
                return 10;
            }

            ------------------------------------------------------(樸實的分割線)

                 “編譯……運行……ok!”老C打了一個響指,“我們的V3.0版本成了!”然后他依法建立了一個AppleGame_V3.0的目錄,將所有文件拷貝到 這個目錄下。“看,由于有了語言的支持,我們很容易的將模塊分開,每個部分都由清晰的接口和歸屬,模塊之間的關(guān)系也更加明顯了。”老C總結(jié)道。
                 “嗯,好像是的。下來我們是要對childlist模塊進行細化嗎?”小P問。
                 “是的是的,這些工作都由你來完成吧,我們現(xiàn)在去吃晚飯,等回來后我們再繼續(xù)。”老C回答。
                 “呵呵,是啊是啊,早去早回,要不一會兒人就多了。”小P回答。
                 兩個人也沒有關(guān)電腦,飛快的向食堂沖去占領(lǐng)有利地形……

            (接著看小P的實現(xiàn)啊)


            posted on 2009-02-19 17:21 Anderson 閱讀(1513) 評論(1)  編輯 收藏 引用

            評論

            # re: 第一桶 從C到C++ 第十碗 老C初論對象模型 小P學(xué)習(xí)基于對象(之一)[未登錄] 2009-02-22 11:22 崔友志

            C++的封裝特性,在c++編程思想上面也有這樣一個和C對比的例子。
            寫的不錯,期待連載  回復(fù)  更多評論   


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            <2009年2月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            1234567

            導(dǎo)航

            統(tǒng)計

            常用鏈接

            留言簿(6)

            隨筆檔案(21)

            文章檔案(1)

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            久久夜色精品国产噜噜麻豆| 青青热久久国产久精品 | 精品多毛少妇人妻AV免费久久| 国产成人无码久久久精品一| 久久美女人爽女人爽| 久久青青草原精品国产不卡| 久久久国产亚洲精品| 精品久久久久中文字幕日本| 伊人久久大香线蕉精品| 久久精品视屏| 一本久久a久久精品vr综合| 精品国产一区二区三区久久| 日日狠狠久久偷偷色综合免费 | 亚洲午夜久久久精品影院| 久久亚洲国产精品123区| 亚洲中文字幕无码久久2017| 午夜不卡888久久| 久久精品极品盛宴观看| 日韩亚洲欧美久久久www综合网| 久久久久久国产精品免费免费 | 66精品综合久久久久久久| 久久夜色精品国产噜噜亚洲a| 久久99国内精品自在现线| 一本色道久久88综合日韩精品 | 久久午夜福利电影| www.久久精品| 中文字幕人妻色偷偷久久| 免费精品久久久久久中文字幕| 国产亚洲欧美成人久久片| 亚洲欧美日韩中文久久| 久久亚洲国产最新网站| 很黄很污的网站久久mimi色| 久久91精品国产91久久麻豆 | 久久精品中文闷骚内射| 无码国内精品久久综合88 | 久久99精品国产99久久| 国产精品美女久久久久久2018| 国产亚洲精久久久久久无码77777| 日韩AV毛片精品久久久| 久久乐国产精品亚洲综合| 精品人妻伦一二三区久久|