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

            longshanks

              C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
              14 Posts :: 0 Stories :: 214 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(10)

            我參與的團隊

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            GP技術的展望——C--
            莫華楓

                C++的復雜是公認的,盡管我認為在人類的聰明智慧之下,這點復雜壓根兒算不上什么。不過我得承認,對于一般的應用而言,C++對程序員產生的壓力還是不 小的。畢竟現在有更多更合適的選擇。僅僅承認復雜,這沒有什么意義。我不時地產生一個念頭:有什么辦法既保留C++的優點,而消除它的缺點和復雜。我知道 D語言在做這樣的事情。但是,D更多地是在就事論事地消除C++的缺陷,而沒有在根本上消除缺陷和復雜性。
                一般而言,一樣東西復雜了,基本上都是因為東西太多。很顯然,C++的語言特性在眾多語言中是數一數二的。于是,我便想到或許把C++變成“C--”,可以治好C++的復雜之病。在探討這個問題之前,讓我們先從C出發,看看C++為何如此復雜。

            C和C++

                盡管存在這樣那樣的不足,比如non-lalr的語法、隱式的指針類型轉換等,但C語言的設計哲學卻是足夠經典的。C語言有一個非正式的分類,認為它既非匯編這樣的低級語言,也非Pascal那樣的高級語言, 而應該算作中級語言,介于其他兩類語言之間。這種分類恰如其分地點出了C語言的特點和理念:以高級語言語法形式承載了低級語言的編程模型。低級語言的特點 是可以直接地描述硬件系統的結構。C則繼承了這個特點。C語言直觀地反映了硬件的邏輯構造,比如數組是內存塊,可以等價于指針。在C語言中,我們可以幾乎 直接看到硬件的構造,并且加以操作。這些特性對于底層開發至關重要。
                然而,C的這種直觀簡潔的模型過于底層和瑣碎,不利于應用在那些構造復雜、變化多樣的應用中。針對C的這些弱點,Bjarne Stroustrup決心利用OOP技術對C語言進行改造,從而促使了C++的誕生。C++全面(幾乎100%)地兼容C,試圖以此在不損失C語言的直觀 和簡潔的情況下,同時具備更強的軟件工程特性,使其具備開發大型復雜系統的優勢。這個目標“幾乎”達到了,但是代價頗為可觀。
                在經歷了80、90年代的輝煌之后,C++的應用領域開始退步。一方面,在底層應用方面,C++的很多特性被認為是多余的。如果不使用這些特性,那么 C++則同C沒有什么差別。相反這些特性的使用,對開發團隊的整體能力提出了更高的要求。因而,在最底層,很多人放棄了C++而回歸了C,因為那些高級特 性并未帶來很多幫助,反而產生了很多負擔。另一方面,在高層開發中,業務邏輯和界面也無需那么多底層的特性和苛刻的性能要求,更多簡單方便、上手容易的語 言相比C++更加適合。C++的應用被壓縮在中間層,隨著業界系統級開發的不斷專業化,C++的使用規模也會越來越小。(當然,它所開發的應用往往都是關 鍵性的,并且是沒有選擇余地的)。實際上,C++在這個層面也并非完美的工具。目前無法取代是因為沒有相同級別的替代品。D或許是個強有力的競爭者,但一 方面出于歷史遺留代碼的規模和應用慣性,另一方面D也并未完全解決C++面臨的復雜性問題,D也很難在可見的將來取代C++。
                實際上,C++的這種尷尬地位有著更深層次的原因。C++的本意是在保留C的底層特性基礎上,增加更好的軟件工程特性。但是,C++事實上并未真正意義上 地保留C的底層特性。回顧一下C的設計理念——直觀而簡潔地反映底層硬件的特性。C++通過兼容C獲得了這種能力。但是這里有個問題,如果我要獲得C的這 種簡單直觀性,就必須放棄C++中的很多高級特性。這里最明顯的一個例子便是pod(plain old data)。
                在C中壓根沒有pod的概念,因為所有的對象都是pod。但是,C++中有了pod。因為C++的對象可能不是一個pod,那么我們便無法象在C當中那樣 獲得直觀簡潔的內存模型。對于pod,我們可以通過對象的基地址和數據成員的偏移量獲得數據成員的地址,或者反過來。但在非pod對象中,卻無法這么做。 因為C++的標準并未對非pod對象的內存布局作出定義,因而對于不同的編譯器,對象布局是不同的。而在C中,僅僅會因為底層硬件系統的差異而影響對象布 局。
                這個問題通常并不顯而易見。但在很多情況下為我們制造了不小的障礙。比如,對象的序列化:我們試圖將一個對象以二進制流的形式保存在磁盤中、數據庫中,或 者在網上傳輸,如果是pod,則直接將對象從基地址開始,按對象的大小復制出來,或傳輸,或存儲,非常方便。但如果是非pod,由于對象的不同部分可能存 在于不同的地方,因而無法直接復制,只能通過手工加入序列化操作代碼,侵入式地讀取對象數據。(這個問題不僅僅存在于C++,其他語言,如java、C# 等都存在。只是它們沒有很強烈的性能要求,可以使用諸如reflect等手段加以處理)。同樣的問題也存在于諸如hash值的計算等方面。這對很多開發工 作造成不小的影響,不僅僅在底層,也包括很多高層的應用。
                究其原因,C++僅僅試圖通過機械地將C的底層特性和OOP等高層特性混合在一起,意圖達到兩方兼顧的目的。但是,事與愿違,OOP的 引入實際上使得C的編程模型和其他更高級的抽象模型無法兼容。在使用C++的過程中,要么只使用C的特性,而無法獲得代碼抽象和安全性方面的好處,要么放 棄C的直觀簡潔,而獲得高層次的抽象能力。反而,由于C和OOP編程模型之間的矛盾,大大增加了語言的復雜性和缺陷數。

            舍棄

                但是,我們可以看到在C++中,并非所有的高級特性都與C的底層特性相沖突。很多使用C而不喜歡C++的人都表示過他們原意接受OB,也就是僅僅使用封裝 。對于RAII,基本上也持肯定的態度。或許也會接受繼承,但也表露出對這種技術帶來的復雜性的擔心。動多態是明顯受到排斥的技術。顯然這是因為動多態破壞了C的編程模型,使得很多本來簡單的問題復雜化。不是它不好,或者沒用,是它打破了太多的東西。
                因而,我們設想一下,如果我們去除動多態特性,那么是否會消除這類問題呢?我們一步步看。
                動多態的一個基本支撐技術是虛函數。在使用虛函數的情況下,類的每一次繼承都會產生一個虛函數表(vtable),其中存放的是指向虛函數的指針。這些虛函數表必須存放在對象體中,也就是和對象的數據存放在一起(至少要關聯在一起)。因而,對象在內存里并不是以連續的方式存放,而被分割成不同的部分,甚至身首異處(詳見《Inside C++ Object Model》)。這便造成了前面所說的非pod麻煩。一旦放棄虛函數和vtable,對象的內存布局中,便不會有東西將對象分割開。所有的對象的數據存儲都是連續的,因而都是pod。在這一點上,通過去除vtable,使得語言回歸了C的直觀和簡單。
                動多態的內容當然不僅僅是一個虛函數,另一個重要的基石是繼承。當然,我們并不打算放棄繼承,因為它并不直接破壞C的直觀性和簡潔性。不同于虛函數,繼承 不是完全為了動多態而生的。繼承最初的用途在于代碼復用。當它被賦予了多態含義后,才會成為動多態的基礎。以下的代碼可以有兩種不同的解讀:
                class B : public A {};
                從代碼復用的角度來看,B繼承自A,表示我打算讓B復用A的所有代碼,并且增加其他功能。而從多態的角度來看,B是一個A的擴展,B和A之間存在is-a的 關系。(B是一個A)。兩者是站在不同層面看待同一個問題。代碼復用,代表了編碼的觀點,而多態,則代表了業務邏輯的觀點。但是,兩者并非實質上的一回 事。在很多情況下,基類往往作為繼承類的某種代表,或者接口,這在編碼角度來看并沒有對等的理解。而這種接口作用,則是動多態的基礎。動多態通過不同的類 繼承自同一個基類,使它們擁有共同的接口,從而可以使用統一的形式加以操作。作為一個極端,interface(或者說抽象基類),僅僅擁有接口函數(即vtable)而不包含任何數據成員。這是純粹的接口。
                然而,這里存在一個缺陷。一個接口所代表的是一組類,它將成為這一組類同外界交互的共同界面。但是,使用基類、或者抽象基類作為接口,實質上是在使用一個 類型來代表一組類型。打個比方,一群人湊在一起出去旅游,我們稱他們這群人為“旅行團”。我們知道旅行團不是一個人,而是一個不同于“人”的概念。動多態 里的接口相當于把一個旅行團當作一個人來看待。盡管這只是邏輯上的,或許一個旅行團的很多行為和一個人頗為相似。但是根本上而言,兩者畢竟不是相同層次的 概念。這樣的處理方法往往會帶來了很多弊端。
                為了使繼承被賦予的這重作用發揮作用,還需要一項非常關鍵的處理:類型轉換。請看以下代碼:
                void func(A* a);
                B b;
                func(&b);
                最后這行代碼施行了動多態,如果B override了A的虛函數的話。很顯然,如果嚴格地從強類型角度而言,&b是不應當作為func的實參,因為兩者類型不匹配。但是如果拒絕接 受&b作為實參,那么動多態將無法進行下去。因此,我們放寬了類型轉換的限制:允許繼承類對象的引用或指針隱式地轉換成基類的引用或指針。這樣, 形如func(&b);便可以順理成章地成為合法的代碼。
                然而,這也是有代價的:
                B ba[5];
                func(ba);
                后面這行函數調用實際上是一個極其危險的錯誤。假設在func()中,將形參a作為一個類型A的數組對待,那么當我們使用ba作為實參調用func()的 時候,會將ba作為A的 數組處理。我們知道,數組內部元素是緊挨著的,第二個元素的位置是第一個元素的基址加上元素的尺寸,以此類推。如果傳遞進來的對象數組是B類型的,而被作 為A類型處理,那么兩者的元素位置將可能不同步。盡管B繼承自A,但是B的尺寸很有可能大于A,那么從第二個元素起,a[1]的地址并非ba[1]的地 址。于是,當我們以a[1]訪問ba時,實際上很可能在ba[0]的內部某個位置讀取,而func()的代碼還以為是在操作ba[1]。這便是C++中的 一個重要的陷阱——對象切割。這種錯誤相當隱蔽,危險性極大。
                由于C++試圖保留C的編程模型,因而保留了指針-數組的等價性。這種等價性體現了數組的本質。這在C中是一項利器,并無任何問題。但在C++中,由于存 在了繼承,以及繼承類的隱式類型轉換,使得這種原本滋補的特性成為了一劑毒藥。換句話說,C++所引入的動多態破壞了C的直觀性。

            舍棄之后

                從上面的分析來看,動多態同C的編程模型是不相容的。因而如果希望得到C的直觀性,并且消除C++的缺陷,必須放棄動多態這個特性。現在來看看放棄之后將會怎樣。
                一旦放棄了動多態,也就放棄了虛函數和vtable。此時,所有的對象都是pod了。那么首當其沖的好處,就是可以進行非侵入的序列化、hash計算等等 操作。由于對象肯定是連續分布的,可以直接地將對象取出進行編碼、存儲、計算和傳輸,而無需了解對象內部的數據結構和含義。另外一個重要的問題也會得到解 決,這就是ABI。在C中統一的ABI很自然地存在于語言中。我們可以很容易地用link將兩個不同編譯器編譯的模塊連接起來,而不會發生問題。但 是,C++中做不到,除非不再使用類而使用純C。目前C++還沒有統一的ABI,即便標準委員會有意建立這樣的規范,實現起來也絕非易事。但是,如果放棄 動多態之后,對象的布局便回歸到C的形態,從而使得ABI不再成為一個問題。
                另一方面,隨著動多態的取消,那么繼承的作用被僅僅局限于代碼復用,不再具有構造接口的作用。我們前面已經看到,繼承類向基類的隱式轉換,是為了使基類能 夠順利地成為繼承類的接口。既然放棄了動多態,那么也就無需基類再承擔接口的任務。那么由繼承類向基類的隱式類型轉換也可以被禁止:
                void func(A* a);
                B b;
                func(&b);  //編譯錯誤,類型不匹配
                進而對象切割也不會發生:
                B ba[5];
                func(ba); //編譯錯誤,類型不匹配
                盡管根據數組-指針的等價性,ba可以被隱式地轉換為B*,但是B*不再能夠隱式地轉換為A*,從而避免了對象的切割。
                問題是,如此簡單地將動多態放棄掉,就如同將水和孩子一起潑掉那樣,實際上放棄了動多態帶來的好處。實際上并非如此。我們放棄動多態這個特性,但并不打算放棄它所具有的功能,而是用另一種技術加以替代。這便是runtime concept(這里這里)。
                不同于以類型為基礎的interface,concept是獨立于類型的系統。concept生來便是為了描述一組類型,因而是接口最理想的實現手段。當concept runtime化之后,便具有了與動多態相同的功能(很多方面還有所超越)。
                runtime concept同樣需要類似vtable的函數分派表,但由于它不是類型,這些分派表無需存放在對象內部,可以獨立放置(可以同RTTI信息放在一起), 并且只需一份。正是基于這個特性,方才保證了所有對象依然是pod,依然能夠保證對象布局的直觀性。
                同樣,runtime concept承擔了接口的任務,但不象動多態那樣依賴于繼承和相應的隱式類型轉換。(通過自動或手動的concept_map)。因而,我們依舊可以禁止基于繼承關系的隱式類型轉換,從而防止對象切割的情況。
                一旦使用concept作為多態的實現手段,反倒促使原本動多態的一些麻煩得到消除。在動多態中,必須指定virtual函數。如此,在一個類中會存在兩 種不同形態的函數,實現動多態的虛函數,和無此功能的普通函數。準確地維護這樣兩種函數,頗有些難度。而且,函數是虛還是不虛,牽涉到系統的設計,必須在 最初構建時確定,否則以后很難修改。但在放棄動多態,使用concept的情況下,只要一個繼承類中,使用相同的簽名覆蓋基類中的函數,便實現了多態。當 進行concept_map,即將接口與類綁定時,只會考慮繼承類的函數,而忽略基類中被覆蓋的函數。于是,只需簡單的覆蓋,便實現了多態的控制。對于是 否多態一個函數,即是否改變基類函數的行為,完全由繼承類控制,在創建基類時不必為此傷神。其結果就是,我們無需在系統設計的最初一刻就操心多態的問題, 而只需根據實現的需要隨時實現。

            其他

                存在大量隱式轉換也是C++常受人詬病的一個方面,(特別是那些Pascal系的程序員)。隱式轉換的目的是帶來方便,使得編碼更加簡潔,減少冗余。同時也使得一些技巧得以施行。但是,隱式轉換的副作用也頗為可觀。比如:
                void fun(short a);
                long a=1248;
                fun(a); //頂多一個警告
                這種轉換存在兩面性:一方面,它可能是合理的,因為盡管a類型long大于short,但很可能存放著short可容納的數值;但另一方面,a的確存在short無法容納的可能性,這便會造成一個非常隱蔽的bug。
                C/C++對此的策略是把問題扔給程序員處理,如果有bug那是程序員的問題。這也算得上合情合理,畢竟有所得必有所失,也符合C/C++的一貫理念。但 終究不是最理想的方式。但是如果象Pascal那樣將類型管得很死,那么語言又會失去靈活性,使得開發的復雜性增加。
                如果試圖禁止隱式類型轉換,那么為了維持函數使用代碼的簡潔性,函數必須對所有的類型執行重載。這大大增加了函數實現的負擔,并且重復的代碼嚴重違背了DRY原則。
                現在或許存在一些途徑,使得在維持絕對強類型的情況下獲得所希望的靈活性。鑰匙可能依然在concept手上。考慮如下的代碼:
                void fun(Integers a);
                long a=1248;
                fun(a);
                longlong b=7243218743012;
                fun(b);
                此處,fun()是一個函數,它的形參是一個concept,代表了所有的整型。這樣,這個函數便可以接受任何一種整型(或者具有整型行為的類型)。我們 相信,在一般的應用下,任何整數都有完全相同的行為。因此,我們便可以很方便地使用Integers這個接口執行對整數的操作,而無需關心到底是什么樣的 整數。
                如此,我們便可以在禁止隱式類型轉換,不使用函數重載的情況下,完成這種函數的編寫。同時可以得到更好的類型安全性。

                強制類型轉換是非常重要的特性,特別是在底層開發時。但也是雙刃劍,往往引來很隱蔽的錯誤。強制類型轉換很多情況下是無理的,通常都是軟件的設計問題造成的。但終究還是有一些情況,需要它來處理。
                設想這樣一個場景:兩個一模一樣的類型,但它們分屬不同的函數。(這種情形盡管不多見,但還是存在的。這往往是混亂設計的結果。當然也有合理的情況,比如 來自兩個不同庫的類型)。我現在需要寫一個函數,能夠同時使用這兩個類型。比較安全一些的,可以用函數重載。但是兩個重載的函數代碼是一樣的,典型的冗余 代碼。當然也可以針對其中一個結構編寫代碼,然后在使用時,對另一個結構的實例執行強制類型轉換。但是,強制類型轉換畢竟不是件好事。因此,我們也可以構 造一個concept,讓它描述這兩個類型。然后在編寫函數時使用這個concept,當這兩個類型都與concept綁定后,便可以直接使用這兩個類 型,而沒有類型安全和代碼冗余的問題。
                (順便提一下,這種方式也可以運用在類型不同的情況下。比如兩個類型不完全相同,但是基本要素都一樣。那么就可以使用concept_map的適配功能, 將兩個類型統一在一個concept下。這種方式相比oop的Adapter模式,更加簡潔。adapter本身是一個container,它所實現的接 口函數,都必須一一轉發到內部的對象,編寫起來相當繁瑣。但在concept_map中,對于那些符合concept描述的函數無需另行處 理,concept會自動匹配,只需對那些不符合要求的函數執行適配。)

                前面說過,指針數組的等價性體現了一種直觀的編程模型。但是,指針和數組畢竟還是存在很多差別,比如指針僅僅表達了一組對象在內存中的位置,但并未攜帶對象數量的信息。因而,當數組退化成指針時,便已經失去了數組的身份:
                void func(int* x);
                int a[20];
                func(a);
                這里,在函數func中已經無法將a作為數組處理,因為無法知道變成int*后的a有多大來避免越界。甚至我們無法把a作為多個對象構成的內存塊看待,因為我們不知道大小。因此,只有顯式地給出數組大小,才能使用:
                void func(int* x, long size);
                但是,在concept的作用下,數組和指針得以依然保持它們的等價性的情況下,解決數組退化問題。考慮這樣兩個函數:
                void func1(Pointer x);
                void func2(Container x);
                其中,Pointer是代表指針的concept,而Container則是代表容器的concept。必須注意的是,Pointer是嚴格意義上的指 針,也就是說無法在Pointer上執行迭代操作。Pointer只能作為指針使用,只具備dereference的能力(很像java的“指針”,不是 嗎?concept在沒有放棄C的底層特性的情況下也做到了。)。而Container則是專門用來表達容器的concept,其基本的特性便是迭代。在 func1中,無法對形參x執行迭代,僅僅將其作為指向一個對象的指針處理,保證其安全性。而對于需要進行迭代操作的func2而言,x則是可以遍歷的。 于是,對于同一個數組a,兩個函數分別從不同的角度對其進行處理:
                int a[20];
                func1(a); //a直接作為指針處理,但不能迭代
                func2(a); //a作為容器處理,可以迭代,并且其尺寸信息也一同傳入
                此處實際上是利用了concept對類型特性的描述作用,將具有兩重性的數組類型(數組a即代表了數組這個容器,也代表了數組的起始地址)以不同特征加以 表達,以滿足不同應用的需求。數組仍然可以退化成指針,C的直觀模型得到保留,在很多特殊的場合發揮作用。但在其他應用場景,可以更加安全地使用數組。
               

            總結

                綜上所述,C++未能真正延續C的直觀簡潔,主要是由于動多態的一些基礎設施破壞了C的編程模型。因而,我們可以通過放棄動多態,及其相關的一些技術,代 之以更加“和諧”的runtime concept,使得C++在基本保留C的編程模型的同時,獲得了相比原來更好的軟件工程特性。至此,這種改變后的C++(如果還能稱為C++的話)擁有 如下的主干特性:
                1、SP,來自于C。
                2、完全pod化。
                3、OB。保留了封裝和RAII。盡管也保留了繼承,但其作用僅限于代碼復用,禁止基于繼承的隱式類型轉換。
                4、GP,包括static和runtime concept。這是抽象高級特性的核心和基石。
                這樣的語言特性實質上比現有的C++更加簡潔,但是其能力更加強大。也比C++更易于貼近C的編程模型,以便適應底層的開發。我不能說這樣的變化是否會產生一個更好的語言,但是我相信這些特性有助于構造更加均衡統一的語言。
            posted on 2008-08-02 20:57 longshanks 閱讀(3000) 評論(14)  編輯 收藏 引用

            Feedback

            # re: GP技術的展望——C-- 2008-08-03 09:07 francis
            每一篇都很精彩,學習!  回復  更多評論
              

            # re: GP技術的展望——C-- 2008-08-03 13:47 陳梓瀚(vczh)
            pod不能有指針,不然你上述的『好處』就囧了。所以我認為C語言的pod其實也不是那么好用的。所以干脆就vtable吧,我還能再模型上建立serialization架構,C就不行了。至少C++還是給了我們選擇的。

            不過話說回來,C++你不用vtable其實也就沒什么關系了,所以還是取決于寫程序的那些人怎么看而已。C++支持的范式很多,不想用不學了就是。但是,還是有很多人想用的。  回復  更多評論
              

            # re: GP技術的展望——C-- 2008-08-03 17:38 Michael Li
            這文章放在當時C++研討會上或許能夠引起些思考,現在來看就沒什么價值了,好還是不好,時間會證明一切的  回復  更多評論
              

            # re: GP技術的展望——C-- 2008-08-03 18:04 longshanks
            @陳梓瀚(vczh):
            的確如此。只是在vtable下,即便沒有指針也無法非侵入地處理對象。但pod可以。C+gp同樣可以在模型上建立serialization架構,但副作用相比oop更小。兩害相權取其輕啊。

            @Michael Li:
            這些想法原本也就是沿著C++未來發展路線的進一步“遐想”。C++09走出了static concept這一步,并且正在以庫的方式模擬runtime concept,那么更進一步便是語言級別的runtime concept了。我只是想看看如果C++擁有語言級別runtime concept,可以獲得什么樣的結果。  回復  更多評論
              

            # re: GP技術的展望——C-- 2008-08-04 19:56 u2usoft
            好久沒有看到這么有意思的文章了  回復  更多評論
              

            # re: GP技術的展望——C-- 2008-08-05 00:11 Computer Worker
            你可以舍棄vtable。C++允許你那么做的。  回復  更多評論
              

            # re: GP技術的展望——C-- 2008-08-05 08:08 longshanks
            @Computer Worker
            舍棄vtable很容易,但如果我還希望同時獲得高級抽象能力呢?  回復  更多評論
              

            # re: GP技術的展望——C-- 2008-08-07 08:40 AlexEric
            其實C++標準一直在完善中,如你所說的
            fun(short a);
            long b
            fun(b);

            這種情形,可以利用模板函數來實現,類型方面應該不是什么大的問題了.
            其實這個還不算什么,在C++中,連 const 類型的變量都可以強制轉換.
            呵呵,關鍵是人如何取舍.  回復  更多評論
              

            # re: GP技術的展望——C-- 2008-08-07 09:49 longshanks
            @AlexEric
            說對了,concept就是模板的發展方向,看C++09。
            說道人如何取舍,對于多數程序員而言,取舍的東西太多,影響他們的發揮。這也是C++發展concept的原因之一。  回復  更多評論
              

            # re: GP技術的展望——C-- 2008-08-07 20:21 Alleluja
            您是OOP的老前輩吧?對于我們這一代年輕的程序員來說,C++似乎是比較遠的東西了。我看到很多人使用Java甚至動態語言,但我則和他們不同,我堅定地選擇C/C++,尤其是在Pascal的學習之后。

            下面講一些我的感受吧,有講的不對的前輩們指正。
            雖然我知道OOP要比GP早,但是卻真實地感受到GP帶來的代碼重用的好處。具體地講,就是我可以想到很多GP的應用,而對于OOP的多型,則想不出多少應用,可能是OOP的實踐較少的緣故吧。我對Java的了解不多,所以我不是那種狂熱的OOP支持者。也可能是我很多時候在用GP解決原來可能需要OOP才能解決的問題造成的緣故,總之我覺得,用GP確實比OOP寫起來要順手。我看網上的留言似乎都對template的調試頗有言辭,可是我的實際經驗確不是這樣的,也就是名字稍微長一點吧,其他沒網上講的這么恐怖。而事實也證明,最近關于C++的進展似乎都是GP方面的,OOP被越來越少地涉及。當然,也可能是算法方面的影響導致我更傾向于GP。所以始終有這樣一種感覺,OOP似乎已經是很遙遠的東西了。

            的確,我覺得C++越來越不是原來那個C with class,而更像C with template。但是C++畢竟是一個要拿來工作的語言。我也很欣賞Pascal,我覺得這種語言也是十分優美的,是和C++在不同方面的優美。但Pascal當初就是為教學而生的,而我現在也極少使用它來真正地寫程序了,為什么?因為C++在實際編碼時的快感是任何語言無法比擬的。現在我多用Pascal構建我的算法,并用類Pascal的偽代碼表示我的想法,這些偽代碼可以很容易地轉換成其他語言而實現。但C/C++的設計初衷和Pascal是不同的。拿我自己來說,最終,構建在Pascal上的時間、空間復雜度,都要由C++來完成,這樣不僅能盡可能減小了復雜度的常數,也簡化了編碼的過程。之所以能這樣,一個方面的原因是在一定Coding經驗積累之后,我既可以在底層控制我程序的每個細節,在適當的時候又可以使用高級抽象來簡化控制。而C++的一些設施,尤其是重載操作符也給代碼的編寫提供不少便利。但這僅僅是就我的應用而言,也許別人就不這么想,所以我還是希望OOP能在C++中完整地保留下來,盡管我不怎么使用它。不過我始終覺得,看問題要長遠,現在看來似乎沒什么用,問題也多的東西,但說不定,以后會有什么新的用途,在新的計算機出現之后,現在的問題可能就解決了呢。畢竟OOP也是經受過時間考驗的。

            所以我希望C++不要成為C with template,而是成為C with class and template。我的切身體驗也證明,即使是Pascal和C++這兩種風格迥異的語言,也能很好地被我使用,“協同工作”。我相信對于C++的各部分也是如此。現在,一直作為看客的Java也在引進C++的部分特性,但這并不是基于Java的經驗,而是C++的經驗。這證明,10多年前C++做出的改進至少有相當一部分是正確的。C++需要創新和傳統,這也是它令我著迷的地方,我希望他能保持。我相信,對于C++而言,現在的困難時期是短暫的,這種永不妥協的精神將引領我們走向光明。  回復  更多評論
              

            # re: GP技術的展望——C-- 2008-08-08 11:28 longshanks
            @Alleluja
            說得好,說得好。兄臺有blog沒,咱也加一個。:)
            oop老前輩可差遠了。我也就是稍微早一些學C++時學了OOP。我心目中更完善的C++應該是有class,但沒有oop。呵呵,有點胡說了。我是指動多態。它的功能用runtime concept代替。我希望的是C with GP,包括static的和dynamic的。  回復  更多評論
              

            # re: GP技術的展望——C-- 2008-12-24 09:42 muf
            好文.

            對于C和C++,目前許多編譯器廠家是合二為一.就是用一個編譯器,既可以編譯 C 代碼, 也可以編譯C++代碼. 這種特性, 常常是通過代碼文件的擴展名來切換的.
            看到這篇文章, 我突然想到, 既然C++有這么多種編程范式, 那么, 應該為不同的范式, 作一個編譯復選項. 這樣, 既保持了 C++的多范式的自由, 又使C++多了一些約束. 畢竟有約束, 才有自由.

            就這篇文章來講, 作者可以選擇 /paradigm:c,class,gp,concept
            如此,不是兩全其美嗎. 我想, 這應該是編譯廠家的好選擇.  回復  更多評論
              

            # re: GP技術的展望——C-- 2009-04-29 13:10 OxFAN
            我先看了google代碼風格指南
            又看了 此文,發現有很多爭議性的東西啊,google的指南幾乎禁用了所有的c++高級特性,比如異常,RTTI,動多態等
            其實c++不能算真正的oo語言,許多新東西是在oop方面的嘗試,您說是么?  回復  更多評論
              

            # re: GP技術的展望——C-- 2009-07-29 08:54 weidagang2046
            樓主的觀點或許正確,但這個例子有明顯不恰當的地方,一看便知:

            class 人 : public 旅行團
            {
            ...
            }

            這種情況不會發生在真實的應用開發中。

            ---------
            然而,這里存在一個缺陷。一個接口所代表的是一組類,它將成為這一組類同外界交互的共同界面。但是,使用基類、或者抽象基類作為接口,實質上是在使用一個類型來代表一組類型。打個比方,一群人湊在一起出去旅游,我們稱他們這群人為“旅行團”。我們知道旅行團不是一個人,而是一個不同于“人”的概念。動多態里的接口相當于把一個旅行團當作一個人來看待。盡管這只是邏輯上的,或許一個旅行團的很多行為和一個人頗為相似。但是根本上而言,兩者畢竟不是相同層次的概念。這樣的處理方法往往會帶來了很多弊端。  回復  更多評論
              

            欧美一级久久久久久久大片| 精品一区二区久久久久久久网站| 久久国产香蕉视频| 久久精品国产一区二区| 人人狠狠综合88综合久久| 综合久久给合久久狠狠狠97色| 伊人久久大香线焦AV综合影院 | 久久精品无码免费不卡| 久久这里都是精品| 久久精品成人国产午夜| 久久人人爽人人爽人人片AV麻豆 | 久久久青草久久久青草| 亚洲精品国精品久久99热| 蜜臀av性久久久久蜜臀aⅴ| 久久一本综合| 国产精品99久久精品| 久久天天躁狠狠躁夜夜不卡| 大香网伊人久久综合网2020| 久久久久人妻一区精品性色av| 青青草国产97免久久费观看| 久久综合九色综合精品| 久久99热这里只频精品6| 久久男人AV资源网站| 久久精品国产精品青草| 91久久婷婷国产综合精品青草| 精品人妻伦九区久久AAA片69| 亚洲午夜无码AV毛片久久| 久久久精品久久久久久| 亚洲天堂久久精品| 久久综合久久综合久久| 久久99精品国产麻豆宅宅| 亚洲乱码精品久久久久..| 老男人久久青草av高清| 久久国产色av免费看| 亚洲精品国产第一综合99久久| 久久久久这里只有精品 | 久久婷婷色综合一区二区| 日韩电影久久久被窝网| 狠狠色丁香婷婷久久综合| 亚洲а∨天堂久久精品9966| 亚洲人成网站999久久久综合 |