• <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初論C++ 潘小P進(jìn)入新天地

                 “還真累啊。”老C揉著自己的胳膊。
                 看著窗明幾凈的實(shí)驗室,清理得整整齊齊的網(wǎng)線和交換機(jī),兩個人都覺得心情很舒暢。吃完了晚飯,兩個人又坐到了白板旁邊。
                 “老C,今天早上的話題還沒有談?wù)撏昴亍?#8221;小P總是充滿好奇心,老C覺得小家伙是個人才。
                 “稍等稍等,等我把這一點(diǎn)看完。”老C用目光匆匆掠過一篇起點(diǎn)上的穿越文,戀戀不舍的轉(zhuǎn)過座椅,“好吧,我們再來review一下我們第二版的C代碼。”


            typedef enum tagFRUIT{ORANGE, APPLE, BANANA} FRUIT;
            typedef void (*PRINT_PROC)(char*);
            typedef struct tagFRUIT_INFO
            {
                FRUIT               fruit_;   
               
            const char* const   name_;
            }FRUIT_INFO;

            void DoPrintFruitName(char* name)
            {
                printf("%s\n", name);
            }

            void DoPrintFruitNameCompany(char* name)
            {
                printf("XJTU's %s\n", name);
            }

            const FRUIT_INFO g_fruitInfo[] =
            {
                ORANGE,    "orange"
                ,APPLE,    "apple"
                ,BANANA,   "banana"
            };

            void
            PrintFruitName(FRUIT fruit, PRINT_PROC printProc)
            {
                int i;
               
                for (
                     i = 0;
                     i < (sizeof(g_fruitInfo)/sizeof(g_fruitInfo[0]));
                     ++i
                    )
                {
                    if (g_fruitInfo[i].fruit_ == fruit)
                    {
                        (*printProc)(g_fruitInfo[i].name_);
                    }
                }
            }

            int main()
            {
                FRUIT fruit;
               
                /* Get the information of fruit. */
                fruit = GetFruitInfo();
                /* Print the name of the fruit. */
                if (/* Print fruit's company. */)
                {
                    PrintFruitName(fruit,
            DoPrintFruitNameCompany);
                }
                else
                {
                    PrintFruitName(
            fruit, DoPrintFruitName)
                }

                return 0;
            }
                 “我們來看看PrintFruitName()函數(shù)的問題,它的一個比較明顯的缺陷是效率。”老C用筆指著代碼說道。
                 “是啊是啊,”有機(jī)會表現(xiàn)一把小P很是高興,“這個函數(shù)做了線性查找,因此它的時間效率應(yīng)當(dāng)是n。”
                 “對,因此對比原版的switch...case...語句的常數(shù)時間效率,我們現(xiàn)在的設(shè)計在時間效率上有損失,你有什么好辦法解決這個問題嗎?”
                 “讓我想想……”小P又開始發(fā)動腦筋,“我覺得我們可以使用一個散列表來儲存這些信息,那么在查找的時候算法的時間復(fù)雜度就是常數(shù)了。”小P找到了解決辦法很是高興,就想著去白板上寫下自己的得意之作。
                 “等等別急。”老C攔住小P,“只要知道了解決之道,代碼是微不足道的,你先不要著急寫代碼……”老C對小P的反應(yīng)速度有些驚訝,“我覺得你的基礎(chǔ)挺好的啊,就是缺乏正確的引導(dǎo)……”
                 “呵呵,謝謝啊,其實(shí)我就是比較油菜而已。”聽了老C的評論小P有些囧,不知道他是表揚(yáng)還是批評。
                 “我們不著急對這一版進(jìn)行改寫,現(xiàn)在你試著使用C++來完成上面的代碼。”老C給小P出了新的題目。
                 “嗯,我看看啊。”小P開始思索起來,“但是有什么不同嗎?如果使用C++的話,我可能還是會寫出第一版那樣的代碼啊……”
                 “所以我說你缺乏正確的引導(dǎo)啊,”老C有些感慨,“因為C++包含了C的部分,因此你完全可以用C的思維方式在C++下編碼,反應(yīng)到代碼風(fēng)格上,就是第一版風(fēng)格的代碼在C++代碼中頻繁出現(xiàn)……”
                 “槑,”小P有些莫名其妙,“那么應(yīng)該怎么做呢?”
                 “嗯,我先簡單的寫寫,然后我們來review。”老C在白板上劃了一道線,將白板分為兩部分,在原來的代碼部分上面寫下C,然后在另一個空白部分的頭部寫下C++。

            class Fruit
            {
            public:
                virtual ~Fruit() {}  

            public:
                virtual void printName() = 0;
            }

            class Orange : public Fruit
            {
            public:
                virtual void printName() { cout <<  "orange" << endl;}
            }

            class Apple : public Fruit
            {
            public:
                virtual void printName() { cout << "apple" << endl; }
            }

            class Banana : public Fruit
            {
            public:
                virtual void printName() { cout << "bnana" << endl; }
            }

            void PrintFruitName(const Fruit& fruit)
            {
                fruit.printName();
            }

            int main()
            {
                /* Fruit factory function. */
                Fruit* fruit = GetFruit();
                PrintFruitName(*fruit);
               
                delete fruit;
               
                return 0;
            }
                
                 “唔,”老C揉揉手,“差不多就是這樣啦,一個很簡單的實(shí)現(xiàn)……與現(xiàn)實(shí)代碼相去甚遠(yuǎn)……”他又想了想,“在實(shí)際情況下我們是不會這樣編碼的,但在這里只是說明一下思維的差異性。”
                 “給我講講吧。”小P等待下文。
                 “在這個實(shí)現(xiàn)里我們使用了C++的多態(tài)特性,也有一種說法是晚綁定……但是無論怎么說,其根源也是信息隱藏。”老C開始比較C和C++的實(shí)現(xiàn),“我們已經(jīng)比較過第一版和第二版的C實(shí)現(xiàn),發(fā)現(xiàn)信息隱藏是進(jìn)行設(shè)計的一個關(guān)鍵點(diǎn)……”
                 “等等老C,什么叫多態(tài)?什么叫晚綁定?”
                 “哦,我們來看看PrintFruitName()函數(shù),你能說清楚這個函數(shù)具體實(shí)現(xiàn)了哪些需求?”如何簡單的解釋這些術(shù)語讓老C覺得有些頭痛。
                 “從代碼看它實(shí)現(xiàn)了對fruit對象名稱的打印……”小P看了看代碼,“但是具體如何做的我看不出來,而且打印的內(nèi)容與函數(shù)的輸入?yún)?shù)有關(guān),不同的參數(shù)會有不同的結(jié)果……”
                 “沒錯!保持統(tǒng)一的接口,而具體行為依照對象而定,不同的對象有不同的行為,這個就是對多態(tài)的簡單解釋。”老C覺得小P還是有些悟性的,“具體在C++語 言中,多態(tài)通過指針和引用來表現(xiàn)。即接口使用父類的指針或引用來表明抽象的統(tǒng)一的接口,而行為根據(jù)父類指針或引用所指向具體子類對象,不同的對象表現(xiàn)出不 同的行為,此乃C++實(shí)現(xiàn)多態(tài)的風(fēng)格,具體來說我們在編程的時候需要使用指向父類的指針或者引用,然后在子類中改寫父類中的虛函數(shù),最后再把子類對象賦值 到父類指針或引用上。如果現(xiàn)在我們需要再增加一個梨這樣的水果,你會怎么做?”
                 “好像很簡單了?”小P試著在白板上寫下如下代碼。

            class Pear : public Fruit
            {
            public:
                virtual void printName() { cout << "pear" << endl; }
            }

                 "然后怎么辦?我可能還需要改寫GetFruit()函數(shù),使得他可以增加一個返回的對象類型?"小P很細(xì)心的發(fā)現(xiàn)一個問題,“但是我覺得我們很難在 GetFruit()函數(shù)中避免類似if..else...或者switch...case..之類的邏輯選擇分支……等等,好像我們實(shí)現(xiàn)的第二版C語言 代碼也存在類似的問題,就是GetFruitInfo()中也無法避免多選擇的判斷分支……”
                 "沒有錯!但是起碼我們對PrintFruitName()函數(shù)的維護(hù)會好很多。"老C很是贊同小P的觀察力,“這個是另外的問題,涉及到一些 factory模式,我們以后再討論……無論怎么樣,我們先來評判一下現(xiàn)在C++的實(shí)現(xiàn)。因為C++的虛函數(shù)實(shí)際上采用散列表的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn),所以我們的 C++程序執(zhí)行效率會比白板另一邊的第二版C代碼好一些。我覺得我以后一定會和你討論一下C++的虛函數(shù)的實(shí)現(xiàn)的,但是今天我們先把這個問題放一邊。”
                 “看來C++還有很多東西是我不了解的啊。”小P開始覺得自己C++課程好像是白上了。
                 “我們來比較一下三個版本的實(shí)現(xiàn)。”老C開始回顧早上的討論,“你發(fā)現(xiàn)什么問題沒有?”
                 “好像一段代碼對其具體實(shí)現(xiàn)了解的越少,它的維護(hù)性就會越好?”小P有些猜測。
                 “呵呵,的確,那么我們通過各種不同的方法達(dá)到了什么樣的看似相同的目的?”老C開始掉小P的胃口。
                 “信息隱藏?”小P不太確定。
                 “信息隱藏是手段,但不是目的。”老C很確定的否決掉小P,“我們達(dá)到的目的是控制問題的規(guī)模!”
                 老C覺得有必要給小P講講哲學(xué):“我們寫軟件的目的是為了解決現(xiàn)實(shí)生活中的具體問題,沒錯吧?”
                 “沒錯,的確是這樣,可是這個和C++有什么關(guān)系的?”小P覺得有些莫名其妙。
                 “那么你覺得使用高級的語言、先進(jìn)的設(shè)計和合理的開發(fā)流程,問題的復(fù)雜度會降低嗎?”
                 “那是啊,問題的復(fù)雜度當(dāng)然會降低啊。”
                 “唉,錯了,問題的復(fù)雜度不會降低的,因為問題的復(fù)雜度是客觀存在,不會因為人主觀的原因而改變!”
                 “槑!”小P有些被震住了,他以前還真是沒有考慮過這樣的問題,“那么為什么我覺得C解決問題比匯編簡單呢?”
                 “那是因為問題的規(guī)模被控制了!”老C開始強(qiáng)調(diào),“因為C的編連器暗地里幫你做了很多事情來控制問題表現(xiàn)給你的規(guī)模,使你感覺好像問題變簡單了——其實(shí)是你面對的問題規(guī)模變小了。打個比方,”老C在白板上找出了上午最早的程序。

            typedef enum tagFRUIT{ORANGE, APPLE, BANANA} FRUIT;

            void PrintFruitName(FRUIT fruit)
            {
                switch (
            fruit)
                {
                case ORANGE:
                    pirntf("orange\n");
                break;
               
                case APPLE:
                    printf("apple\n");
                break;
               
                case BANANA:
                    printf("banana\n");
                break;
               
                default:
                    return;  
                }
            }


            int main()
            {
                FRUIT fruit;
               
                /* Get the information of fruit. */
                fruit = GetFruitInfo();
                /* Print the name of the fruit. */
                PrintFruitName(fruit);

                return 0; 
            }

                 “看看吧,根據(jù)你剛才的發(fā)現(xiàn),是不是如果需求發(fā)生變化時,GetFruitInfo()和PrintFruitName()這兩個函數(shù)都要發(fā)生變更?”老C指著代碼問小P。
                 “是啊,沒有錯。”
                 “現(xiàn)在我們代碼的規(guī)模還很小,如果我們在多處需要涉及到水果的信息,那么根據(jù)這種風(fēng)格,如果需求發(fā)生變更時,是不是每個地方都需要對源代碼進(jìn)行修改?”老C開始循循善誘。
                 “嗯,好像是的。我們這里只是打印了水果的名稱,如果我們還需要水果的形狀,水果的顏色,哦,好像我們維護(hù)時候的復(fù)雜度會按照問題的規(guī)模成倍的增長。”
                 “是啊是啊,這就叫牽一發(fā)而動全身。”老C總結(jié)道,“那么第二個做法呢?”
                 “好像可以好一些,起碼我們只用修改某些表格,哦,還要修改哪個GetFruitInfo()的函數(shù),但是起碼問題的擴(kuò)散沒有那么嚴(yán)重了……”小P現(xiàn)在隱約覺得自己好像腦袋里面有只手,快要抓住什么東西卻又抓不到,有些迷蒙起來。
                 “但是維護(hù)表格的工作量也不小啊。”老C補(bǔ)充道,“那么最后一種做法呢?”
                 “我個人感覺好像C++編連器在幫助我們維護(hù)這些表格?”小P好像猛的明白過來,“比如將虛函數(shù)的實(shí)現(xiàn)隱藏在編連器的后面……”他又開始有些迷蒙……
                 “是的,是這樣的。”老C點(diǎn)點(diǎn)頭,“我們實(shí)際上面對問題的復(fù)雜度并沒有改變,只是由于語言的幫助,我們可以設(shè)計出一些代碼來限制我們接觸問題的規(guī)模,把一 個復(fù)雜的問題逐步劃分到我們自己可以理解的規(guī)模上來,這樣好像問題變簡單了一樣。”老C接著說道,“這就是我為什么說我們所使用的語言會影響到我們思考問 題的方法,而我們思考問題的方法會反過來影響我們編碼的風(fēng)格。”
                 小P突然感覺自己來到了一個更寬闊的世界,好像自己突然明白了什么又好像不是很明白……小P開始覺得C++充滿了神秘和樂趣,下決心一定要把C++學(xué)好。
                 “老C,和你聊聊太有收獲了,我要把這些代碼抄下來回去再看看,體會體會,”小P做激昂狀,“我一定要在3年內(nèi)學(xué)好C++……”
                 “等等,3年時間好像太短了吧?”老C有些被雷到了。
                 “?”
                 “建議你看看《Teach Yourself Programming in Ten Years》這篇文章吧,急是急不來的。”老C覺得年輕人就是浮躁。
                 “哦?好,那我回宿舍后查查這篇文章。但是以后你要多教教我啊。”
                 “互相討論,互相學(xué)習(xí)。”老C謙虛道,“C++還有template種類的編程風(fēng)格,但是我想我們還是討論到此吧,時間也不早了,我們回去吧。”
                 “好啊,回去打一盤魔獸,看看誰更厲害!”小P決定也給老C當(dāng)一回老師過過癮!

                 (欲知后事如何,且聽下回分解)

            posted on 2009-01-18 14:26 Anderson 閱讀(2192) 評論(11)  編輯 收藏 引用

            評論

            # re: 第一桶 從C到C++ 第二碗 陳老C初論C++ 潘小P進(jìn)入新天地 2009-01-18 19:55 蟲牙

            Teach Yourself Programming in Ten Years
            http://norvig.com/21-days.html
              回復(fù)  更多評論   

            # re: 第一桶 從C到C++ 第二碗 陳老C初論C++ 潘小P進(jìn)入新天地 2009-01-18 20:14 ZJOK

            很好,再詳細(xì)點(diǎn),通俗點(diǎn)!!  回復(fù)  更多評論   

            # re: 第一桶 從C到C++ 第二碗 陳老C初論C++ 潘小P進(jìn)入新天地 2009-01-18 21:29 orz

            太~~太~~~有才了~~  回復(fù)  更多評論   

            # re: 第一桶 從C到C++ 第二碗 陳老C初論C++ 潘小P進(jìn)入新天地 2009-01-18 22:20 adon

            是講設(shè)計模式的吧,我是從設(shè)計模式才明白面向?qū)ο蟮?nbsp; 回復(fù)  更多評論   

            # re: 第一桶 從C到C++ 第二碗 陳老C初論C++ 潘小P進(jìn)入新天地 2009-01-19 09:26 weimi

            頂樓主!
            用簡單的代碼說明抽象的問題,很好!  回復(fù)  更多評論   

            # re: 第一桶 從C到C++ 第二碗 陳老C初論C++ 潘小P進(jìn)入新天地[未登錄] 2009-01-19 10:34 Anderson

            @adon
            哦,設(shè)計模式是內(nèi)容的一部分,主要包括
            1. 從C到C++
            1.1 首先接觸類
            1.2 越早接觸UML越好
            1.3 直接學(xué)習(xí)C++習(xí)語和設(shè)計模式
            1.4 代碼格式和編程素質(zhì),寫優(yōu)雅的代碼
            1.5 C++對象模型
            2. 過程,工具,人。
            2.1 IDE,配置管理
            2.2 漸進(jìn)的迭代式開發(fā)
            2.3 以需求(用例)為引導(dǎo)
            3. 討論一些高級技巧
            3.1 異常安全性
            3.2 線程安全
            4. 模版與meta programming
            5. STL和BOOST,TR1
            6. Qt和MFC
            7. 其他,可能包括一些XML之類

            不會按照順序?qū)懀瑧?yīng)當(dāng)是穿插起來的吧。后面的還沒有想好,接下來應(yīng)該討論一些從C過渡到C++的故事,中間穿插一些關(guān)于IDE,配置管理和C++對象模型的討論吧  回復(fù)  更多評論   

            # re: 第一桶 從C到C++ 第二碗 陳老C初論C++ 潘小P進(jìn)入新天地 2009-01-19 10:58 你好

            你好,在你第一篇文章中我發(fā)現(xiàn)2個bug,
            請作者核實(shí)下:
            typedef enum tagFRUIT{ORANGE, APPLE, BANANA} FRUIT;

            typedef struct tagFRUIT_INFO
            {
            FRUIT fruit_;
            const char* name_;
            //const char* const name_;
            } FRUIT_INFO;

            const FRUIT_INFO test[] = {
            {ORANGE,_T("xxx")},
            {APPLE,_T("fff")}
            };
              回復(fù)  更多評論   

            # re: 第一桶 從C到C++ 第二碗 陳老C初論C++ 潘小P進(jìn)入新天地[未登錄] 2009-01-19 15:04 Anderson

            @你好
            const char* const name_ 指的是name_所指向的字符串內(nèi)容不能被改變,而且name_這個指針也不能被改變,指向其他內(nèi)容是不行的。

            初始化結(jié)構(gòu)體的時候,{}也是可以不用的,不過用上更清晰一些。謝謝。
            至于_T,應(yīng)當(dāng)是windows開發(fā)環(huán)境定義的宏吧,用于在windows頭文件定義的WCHAR和CHAR之間做編譯選擇用的,標(biāo)準(zhǔn)C中并沒有定義這個宏,而且
            不涉及國際化的時候wchar_t這個類型也是可以不用的吧。

            我用的是最新的GCC,代碼可以編譯通過。VS2005上也試了一下,可以通過。

            還是謝謝您的評論。  回復(fù)  更多評論   

            # re: 第一桶 從C到C++ 第二碗 陳老C初論C++ 潘小P進(jìn)入新天地[未登錄] 2009-01-22 17:01 Len

            現(xiàn)在程序員小說很流行,這個系列看來要用大話文來解析細(xì)節(jié)了,非常不錯  回復(fù)  更多評論   

            # re: 第一桶 從C到C++ 第二碗 陳老C初論C++ 潘小P進(jìn)入新天地 2009-03-22 21:09 coast

            很有才。  回復(fù)  更多評論   

            # re: 第一桶 從C到C++ 第二碗 陳老C初論C++ 潘小P進(jìn)入新天地 2009-09-17 15:01 亂78糟

            寫出了我想說但表達(dá)不出來的 內(nèi)容,關(guān)注ing...  回復(fù)  更多評論   


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


            <2025年6月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            293012345

            導(dǎo)航

            統(tǒng)計

            常用鏈接

            留言簿(6)

            隨筆檔案(21)

            文章檔案(1)

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            日产精品久久久久久久| 久久精品中文字幕大胸| 999久久久免费国产精品播放| 无码任你躁久久久久久久| 91久久香蕉国产熟女线看| 精品久久人人做人人爽综合| 亚洲国产成人久久综合碰| 久久久亚洲欧洲日产国码是AV| 色综合久久中文字幕无码| 久久国产精品99精品国产| 亚洲国产精品婷婷久久| 7777精品伊人久久久大香线蕉| 久久亚洲AV成人无码软件| 欧美伊人久久大香线蕉综合| 国产成人精品综合久久久久| 国产精品伊人久久伊人电影| 国产精品亚洲综合久久| 国产精品日韩欧美久久综合| 青草国产精品久久久久久| 欧美性猛交xxxx免费看久久久| 嫩草影院久久国产精品| 久久人人爽人人爽人人AV| 国产香蕉久久精品综合网| 久久久久一本毛久久久| 久久久国产精品| 亚洲国产天堂久久久久久| 性做久久久久久久久浪潮| 久久99国产精品久久99小说 | 久久99精品国产麻豆不卡| 91精品国产综合久久香蕉 | 伊人久久精品线影院| 91久久香蕉国产熟女线看| 怡红院日本一道日本久久 | 天天综合久久久网| 久久亚洲av无码精品浪潮| 久久久这里有精品| 国产精品久久久久天天影视| 精品国产综合区久久久久久| 欧美粉嫩小泬久久久久久久| 91久久精品91久久性色| 久久这里有精品|