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

            我參與的團隊

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

                本文來源于TopLanguage Group 上的一次討論(這里這里這里 )。pongba提出:C++的抽象機制并不完善,原因是為了性能而做的折中,未來隨著計算能力的提高到一定程度,人們就能夠忽略更好的抽象所帶來的負面效應。就此諸老大各自提出高見,受益良多啊。經過討論,我基本上理解了pongba的想法。但我覺得等待計算機的性能提高太消極了。我相信隨著編程技術的發展,這種最優抽象造成的性能損失將會越來越小。這種途徑將會更快地讓人們接受最優抽象形式。

                 在“C++ Template”一書中,將多態總結為三種主要類型:runtime bound、static unbound和runtime unbound。其中runtime bound就是我們通常所說的動多態,OOP的核心支柱(廣義上OOP還包括Object Base(OB,僅指類型封裝等OO的基本特性),但有時也會將OB和OOP分開,OOP單指以OO為基礎的動多態。這里使用狹義的OOP含義); static unbound就是靜多態,通過模板實現。而runtime unbound則是一種不常見的形式。早年的SmallTalk具有這種形式,現在的ruby也引入這種機制。
                 在主流的(靜態)語言中,我們會面臨兩種類型的多態需求:對于編譯期可以確定類型的,使用靜多態,比如實例化一個容器;對于運行期方能確定類型的,則使用 動多態。而runtime unbound也可以用于運行期類型決斷。于是,便有了兩種運行期多態。這兩種多態的特性和他們的差異,是本文的核心。實際上,相比動多態, runtime unbound多態為我們提供了更本質的運行時多態手段,我們可以從中獲得更大的收益。但是鑒于一些技術上的困難,runtime unbound多態無法進入主流世界。不過,由于新的編程技術的出現,使得這種更好的運行時多態形式可以同動多態一比高下。

            動多態   

                廢話少說,讓我們從一個老掉牙的案例開始吧:編寫一個繪圖程序,圖形包括矩形、橢圓、三角形、多邊形等等。圖形從腳本(比如xml)中讀出,創建后保存在一個容器中備查。通過遍歷容器執行圖形繪制。
                就這么個題目,很簡單,也很熟悉,解釋OOP的動多態最常用的案例。下面我們就從動多態實現開始。
                首先定義一個抽象基類,也就是接口:

                class IShape

                {

                    virtual void load(xml init)=0;

                    virtual void draw(monitor m)=0;

                    ...

                };

                然后定義各種圖形類,并從這個接口上繼承:

                class Rectangle: public IShape

                {

                    void load(xml init) {...}

                    void draw(monitor m) {...}

                    ...

                };

                class Ellipse: public IShape

                {

                    void load(xml init) {...}

                    void draw(monitor m) {...}

                    ...

                };

                ...

             

                void DrawShapes(monitor m, vector<IShape*> const& g)

                {

                    vector<IShape*>::const_iterator b(g.begin()), e(g.end());

                    for(; b!=e; ++b)

                    {

                        (*b)->draw(m);

                    }

                }

                ...

                現在可以使用這些圖形類了:

                vector<IShape*> vg;

                vg.push_back(new Rectangle);

                vg.push_back(new Ellipse);

                ...

                DrawShapes(crt, vg);

                通過接口IShape,我們可以把不同的圖形類統一到一種類型下。但是,通過虛函數的override,由圖形類實現IShape上的虛函數。這可以算老 生常談了。動多態的核心就是利用override和late bound的組合,使得一個基類可以在類型歸一化的情況下,擁有繼承類的語義。OOP設計模式大量運用這種技術,實現很多需要靈活擴展的系統。

            Runtime Unbound

                Runtime Unbound多態混合了靜多態和動多態的特征,即既有類型泛化,又是運行時決斷的。一個最典型的例子就是ruby的函數:
                class x
                   def fun(car)
                        car.aboard
                    end
                end
                這個案例非常明確地展示出了Runtime Unbound多態的特點。car參數沒有類型,這里也不需要關心類型,只要求car對象有一個aboard方法即可。由于ruby是動態語言,能夠運行時檢測對象的特征,并動態調用對象上的方法。
                在Runtime Unbound的思想指導下,我們利用一種偽造的“動態C++”,把上面的繪圖例子重新編寫:

                class Rectangle

                {

                    void load(xml init) {...}

                    void draw(monitor dev) {...}

                    ...

                };

                class Ellipse

                {

                    void load(xml init) {...}

                    void draw(monitor dev) {...}

                    ...

                };

                ...

                void DrawShapes(monitor dev, vector<anything> const& g)

                {

                    vector<IShape>::const_iterator b(g.begin()), e(g.end());

                    for(; b!=e; ++b)

                    {

                        (*b).draw(dev);

                    }

                }

                ...

                vector<anything> vg;

                vg.push_back(Rectangle(...));

                vg.push_back(Ellipse(...));

                ...

                DrawShapes(crt, vg);

                圖形類不再從抽象接口IShape繼承,而用關鍵字anything實例化vector<>模板。這個虛構的anything關鍵字所起的作 用就是使得vector能夠接受不同類型的對象。當DrawShapes()函數接收到存放圖形對象的容器后,遍歷每一個對象,并且調用對象上的draw ()函數,而不管其類型。
                從這段代碼中,我們可以看出Runtime Unbound多態帶來的好處。所有圖形類不再需要歸一化成一個類型(抽象接口)。每個類只需按照約定,實現load、draw等成員函數即可。也就是 說,這些圖形類解耦合了。一旦類型解耦,便賦予我們很大的自由度。最典型的情況就是,我們需要使用一個其他人開發的圖形類,并且無法修改其實現。此時,如 果使用動多態,就很麻煩。因為盡管這些圖形類都擁有load、draw等函數,但畢竟不是繼承自IShape,無法直接插入容器。必須編寫一個繼承自 IShape的適配器,作為外來圖形類的包裝,轉發對其的訪問。表面上,我們只是減少一個接口的定義,但Runtime Unbound多態帶來的解耦有著非凡的意義。因為類耦合始終是OOP設計中的一個令人頭痛的問題。在后面,我們還將看到建立在Runtime Unbound多態基礎上的更大的進步。
                然而,盡管Runtime Unbound多態具有這些優點,但因為建立在動態語言之上,其自身存在的一些缺陷使得這項技術無法廣泛使用,并進入主流。
                Runtime Unbound多態面臨的第一個問題就是類型安全。確切的講是靜態類型安全。
                本質上,Runtime Unbound多態(動態語言)并非沒有類型安全。當動態語言試圖訪問一個未知類型對象的成員時,會通過一些特殊機制或特殊接口獲得類型信息,并在其中尋 找所需的對象成員。如果沒有找到,便會拋出異常。但是,傳統上,我們希望語言能夠在編譯期得到類型安全保證,而不要在運行時才發現問題。也就是說, Runtime Unbound多態只能提供運行時類型安全,而無法得到靜態類型安全。
                第二個問題是性能。Runtime Unbound需要在運行時搜尋類型的接口,并執行調用。執行這類尋找和調用的方法有兩種:反射和動態鏈接。
                反射機制可以向程序提供類型的信息。通過這些信息,Runtime Unbound可以了解是否存在所需的接口函數。反射通常也提供了接口函數調用的服務,允許將參數打包,并通過函數名調用。這種機制性能很差,基本上無法用于稍許密集些的操作。
                動態鏈接則是在訪問對象前在對象的成員函數表上查詢并獲得相應函數的地址,填充到調用方的調用表中,調用方通過調用表執行間接調用。這種機制相對快一些,但由于需要查詢成員函數表,復雜度基本上都在O(n)左右,無法與動多態的O(1)調用相比。
                這些問題的解決,依賴于一種新興的技術,即concept。concept不僅很消除了類型安全的問題,更主要的是它大幅縮小了兩種Runtime多態的性能差距,有望使Runtime Unbound成為主流的技術。

            concept

                隨著C++0x逐漸浮出水面,concept作為此次標準更新的核心部分,已經在C++社群中引起關注。隨著時間的推移,concept的潛在作用也在不斷被發掘出來。
                concept主要用來描述一個類型的接口和特征。通俗地講,concept描述了一組具備了共同接口的類型。在引入concept后,C++可以對模板參數進行約束:
                concept assignable<T> {
                    T& operator=(T const&);
                }
                template<assignable T> void copy(T& a, T const& b) {
                    a=b;
                }
                這表示類型T必須有operator=的重載。如果一個類型X沒有對operator=進行重載,那么當調用copy時,便會引發編譯錯誤。這使得類型參數可以在函數使用之前便能得到檢驗,而無需等到對象被使用時。
                另一方面,concept參與到特化中后,使得操作分派更加方便:
                concept assignable<T> {
                    T& operator=(T const&);
                }
                concept copyable<T> {
                    T& T::copy(T const&);
                }
                template<assignable T> void copy(T& a, T const& b) {    //#1
                    a=b;
                }
                template<copyable T> void copy(T& a, T const& b) {    //#2
                    a.copy(b);
                }
                X x1,x2; //X支持operator=操作符
                Y y1,y2; //Y擁有copy成員函數
                copy(x1, x2);    //使用#1
                copy(y1, y2);    //使用#2
                在靜多態中,concept很好地提供了類型約束。既然同樣是Unbound,那么concept是否同樣可以被用于Runtime Unbound?應當說可以,但不是現有的concept。在Runtime Unbound多態中,需要運行時的concept。
                依舊使用繪圖案例做一個演示。假設這里使用的"C++"已經支持concept,并且也支持了運行時的concept:

                class Rectangle

                {

                    void load(xml init) {...}

                    void draw(monitor dev) {...}

                    ...

                };

                class Ellipse

                {

                    void load(xml init) {...}

                    void draw(monitor dev) {...}

                    ...

                };

                ...

                concept Shape<T> {

                    void T::load(xml init);

                    void T::draw(monitor dev);

                }

                ...

                void DrawShapes(monitor dev, vector<Shape> const& g)

                {

                    vector<IShape>::const_iterator b(g.begin()), e(g.end());

                    for(; b!=e; ++b)

                    {

                        (*b).draw(dev);

                    }

                }

                ...

                vector<Shape> vg;

                vg.push_back(Rectangle(...));

                vg.push_back(Ellipse(...));

                vg.push_back(string("xxx"));    //錯誤,不符合Shape concept

                ...

                DrawShapes(crt, vg);

                乍看起來沒什么特別的,但是請注意vector<Shape>。這里使用一個concept,而不是一個具體的類型,實例化一個模板。這里的意思是說,這個容器接受的是所有符合Shape concept的對象,類型不同也沒關系。當push進vg的對象不符合Shape,便會發生編譯錯誤。

                 但是,最關鍵的東西不在這里。注意到DrawShapes函數了嗎?由于vector<Shape>中的元素類型可能完全不同。語句 (*b).draw(dev);的語義在靜態語言中是非法的,因為我們根本無法在編譯時具體確定(*b)的類型,從而鏈接正確的draw成員。而在這里, 由于我們引入了Runtime Unbound,對于對象的訪問鏈接發生在運行時。因此,我們便可以把不同類型的對象存放在一個容器中。

                concept在這里起到了類型檢驗的作用,不符合相應concept的對象是無法放入這個容器的,從而在此后對對象的使用的時候,也不會發生類型失配的 問題。這也就在動態的機制下確保了類型安全。動多態確保類型安全依靠靜態類型。也就是所有類型都從一個抽象接口上繼承,從而將類型歸一化,以獲得建立在靜 態類型系統之上的類型安全。而concept的類型安全保證來源于對類型特征的描述,是一種非侵入的接口約束,靈活性大大高于類型歸一化的動多態。

                如果我們引入這樣一個規則:如果用類型創建實例(對象),那么所創建的對象是靜態鏈接的,也就是編譯時鏈接;而用concept創建一個對象,那么所創建的對象是動態鏈接的,也就是運行時鏈接。

                在這條規則的作用下,下面這段簡單的代碼將會產生非常奇妙的效果:

                class nShape

                {

                public:

                    nShape(Shape g, int n) : m_graph(g), m_n(n) {}

                    void setShape(Shape g) {

                        m_graph=g;

                    }

                private:

                    Shape    m_graph;

                    int        m_n;

                };

                在規則的作用下,m_graph是一個動態對象,它的類型只有在運行時才能明確。但是無論什么類型,必須滿足Shape concept。而m_n的類型是確定的,所以是一個靜態對象

                這和傳統的模板有區別嗎?模板也可以用不同的類型參數定義成員數據。請看如下代碼:

                Rectangle r;

                Ellipse e;
                 nShape(r, 10);

                 nShape.setShape(e);   //對于傳統模板而言,這個操作是非法的,因為e和r不是同一種類型

                動態對象的特點在于,我們可以在對象創建后,用一個不同類型的動態對象代替原來的,只需要這些對象符合相應的concept。這在靜態的模板上是做不到的。

                現在回過頭來看一下用concept實例化模板的情形。我們知道,用一個類型實例化一個模板,得到的是一個類,或者說類型。而用一個concept實例化 一個模板,得到的又是什么呢?還是一個concept。那么vector<Shape>是一個concept,因而它的實例是動態的對象。當 然,實際上沒有必要把vector<Shape>的實例整個地當成動態對象,它只是具有動態對象的行為特征。在實現上,vector< Shape>可以按照普通模板展開,而其內部由concept模板實參定義的對象作為動態對象處理即可。一個由concept實例化的模板的對象作為語義上的動態對象
                下面的代碼則引出了另一個重要的特性:
                vector<float> vFloat;    //靜態對象的容器,內部存放的都是靜態對象,屬于同一類型float
                vector<Shape> vShape; //動態對象的容器,內部存放動態對象,都符合Shape
                同一個類模板,當使用類型實例化,執行static unbound多態使用concept實例化,執行runtime unbound多態。兩者的形式相同。也就是說static多態同runtime多態以相同的形式表達。 由于concept的加入,兩種完全不同的多態被統一在同一個模型和形式下。實際上,static和runtime unbound多態可以看作同一個抽象體系的兩個分支,分別處理不同情況的應用。而形式上的統一,則更加接近抽象體系的本質。同時,也使得兩種 unbound多態的差異被后臺化,使用者無需額外的工作,便可以同時獲得動態和靜態的抽象能力。同時,兩種多態所展示的邏輯上的對稱性,也暗示了兩者在 本質上的聯系。這里統一的形式,便是這種對稱性的結果。
                對于模板函數,則會表現出更加有趣的特性(這個函數模板有些特別,不需要template關鍵字和類型參數列表,這是我偽造的。但由于concept的使用,它本質上還是一個模板):
                void draw(Shape g);
                這個函數接受一個符合Shape的參數。如果我們用一個靜態對象調用這個函數:
                Rectangle r;
                draw(r);
                那么,就執行static unbound,實例化成一個完完整整的函數,同傳統的函數模板一樣。
                如果用一個動態對象調用這個函數:
                Shape g=Cycle();
                draw(g);
                g=Rectangle();
                draw(g);
                那么,就執行runtime unbound,生成一個等待運行時鏈接的函數。上面的兩次調用,分別進行了兩次運行時鏈接,以匹配不同的動態對象。
                這樣,我們可以通過函數調用時的參數對象,來控制使用不同的多態形式。更復雜的情況就是用一個函數的返回值調用另一個函數,這樣構成的調用鏈依然符合上述的調用控制原則。
                下面,我們將看到Runtime Unbound多態的一個精彩表演:
                //假設,我們已經定義了Rectangle、Cycle、Square、Ellipse、Trangle五個類,
                // 分別map到Rectangles、Cycles、Squares、Ellipses、Trangles五個concept上,
                // 這些concept都refine(可以不正確地理解為繼承吧)自Shape。
                void draw(monitor dev, Rectangles r); //#3
                void draw(monitor dev, Cycles c);       //#4
                void draw(monitor dev, Squares s);    //#5
                void draw(monitor dev, Ellipses e);    //#6
                void draw(monitor dev, Trangles t);    //#7
                //此處定義一個Shape的動態對象
                Shape g=CreateShapeByUserInput();    //這個函數根據用戶輸入創建圖形對象,所以圖形對象的類型只能到運行時從能確定。
                draw(crt, g);
                好了,現在該調用哪個版本的draw?根據用戶的輸入來。換句話說,調用哪個版本的draw,取決于CreateShapeByUserInput()函數的返回結果,也就是用戶輸入的結果。如果CreateShapeByUserInput() 返回Rectangle的動態對象,那么執行#3;如果返回的是Trangle對象,那么執行#7。這是一種動態分派的操作。在運行時concept的作 用下,實現起來非常容易。對draw的調用最終會被轉換成一個concept需求表,來自draw函數,每一項對應一個函數版本,并且指明了所對應的 concept。動態對象上也有一個concept表,每一項存放了這個對象所符合的concept。用這兩個表相互匹配,可以找到g對象的 concept最匹配的那個draw版本,然后調用。
                這實際上是將重載決斷放到運行時進行,而concept在其中起到了匹配參數的作用。
                這樣的做法同利用rtti信息執行類型分派調用類似:
                void draw_impl(monitor dev, Rectangle& r);
                void draw_impl(monitor dev, Cycle& c);
                void draw_impl(monitor dev, Square& s);
                void draw_impl(monitor dev, Ellipse& e);
                void draw_impl(monitor dev, Trangle& t);
                void draw_impl(monitor dev, Shape& g) {
                    if(typeif(g)==typeid(Rectangle))
                        draw_impl(dev, (Rectangle&)g);
                    else if(typeif(g)==typeid(Cycle))
                        draw_impl(dev, (Cycle&)g);
                    ...
                }
                但是,他們卻有著天壤之別。首先,rtti分派是侵入的。如果需要增加一個圖形,需要在draw函數中增加分派代碼。而Runtime Unbound方案則只需要用新的concept重載draw函數即可。
                其次,rtti版本有多少圖形類,就需要多少if...else...,而Runtime Unbound則是一對多的。如果有幾個圖形類內容不同,但有相同的接口,符合同一個concept,那么只需針對concept編寫一個函數版本即可。 比如,如果有一個特別的CycleEx類,使用外界正方形的左上角/右下角坐標描述,正好符合Ellipses concept,那么只需將CycleEx map到Ellipses上即可,無需多加任何代碼。
                最后,rtti需要獲取類型信息,然后做線性比較,性能無法優化。但Runtime Unbound通過concept表的相互匹配,僅牽涉數值操作,有很大的優化空間。
                那么這樣一種運行時分派有什么好處呢?我們看到圖形類上的draw函數接受一個monitor類型參數,它代表設備。如果哪一天需要向另一種設備,比如 printer,輸出圖形,那么就需要在圖形類上增加另一個版本的draw函數。如果類是別人開發的,那么就增加溝通的負擔。如果類是外來的,我們無法修 改,那么只能通過adapter之類的笨拙手段處理。為了讓monitor之類同圖形本身沒有關聯的東西分離,應當使用自由函數執行draw操作。但普通 函數只能接受確定的類型重載,而傳統的函數模板則限于編譯期使用,無法進行運行時分派。所以,如果能夠使用concept重載函數,并且賦予 Runtime Unbound機能,那么便可以用最簡單的形式針對一類類型進行處理,效能高得多。

            運行時concept

               語言層面的concept無法做到這些,因為它是編譯期機制。為此,我們需要有一種運行時的concept,或者說二進制級別的concept。

                一個concept包含了與一個或若干個類型有關的一組函數,包括成員函數和自由函數。于是,我們就可以用一個類似“虛表”的函數指針表(暫且稱為 ctable吧)存放concept指定的函數指針。這樣的ctable依附在動態對象上,就像vtable一樣。每個對象都會匹配和map到若干個 concept。因此,每個動態對象會有一個concept表,其中存放著指向各ctable的指針,以及相應的concept基本信息。

                當一個“用戶”(函數或模板)需要在運行時鏈接到對象上的時候,它會提交一個concept的代碼(全局唯一)。系統用這個代碼在動態對象的 concept表上檢索,獲得指向所需concept的指針,并且填寫到“用戶”給出的一個“插入點”(一個指針)中。隨后“用戶”便可以直接通過這個 “插入點”間接調用所需的函數,成員或自由函數。

                在這里,concept的巧妙之處在于,將一族函數集合在一起,作為一個整體(即接口)。那么,在執行運行時匹配的時候,不再是一個函數一個函數地查詢, 可以一次性地獲知這些函數是否存在。這就很容易地規避了類型安全保證操作的損耗。如果使用hash查詢,那么可以在O(1)實現concept匹配。另 外,一個concept的hash值可以在編譯時計算好,運行時鏈接只需執行hash表檢索,連hash值計算也可以省去。

                一個動態對象可以直接用指向concept ctable的指針表示。在不同concept之間轉換,相當于改變指針的指向,這種操作非常類似OOP中的dynamic_cast。

                對于如下的動態對象定義:

                Shape g=Cycle();

                會創建一個Cycle對象,在對象上構建起一個concept表,表中對應Cycle所有符合的concept。并且建立一組ctable,每個 ctable對應一個concept。每個concept表項指向相應的ctable。而符號g則實際上是指向所建立對象的Shapes ctable的指針。

                對于函數:

                void draw(Shape g);

                draw(g);

                調用g時,由于draw的參數是Shape concept,而g正是draw所需的concept,所以無需在對象g的concept表上匹配,可以直接使用這個ctable指針。這就是說,只要 所用動態對象(g)的concept同使用方(draw函數)能夠匹配,便可以直接使用指向ctable的指針鏈接(編譯時鏈接),無需在運行時重新匹 配。只有發生concept轉換時,才需要在concept表中搜索,獲得所需的ctable指針:

                Swappable s=g; //Swappable是另一個concept

                這種情況同dynamic_cast極其相似。也可以模仿著采用concept_cast之類的操作符,使得concept轉換顯式化,消除隱式轉換的問題(強concept化)。

                所以,Runtime Unbound在運行時concept的作用下,具有同動多態相同的底層行為。因而,他們的性能也是一樣的。很多用于動多態的方案和算法都可以直接用于運行時concept。

            Runtime Unbound和Runtime Bound

                對于runtime unbound同runtime bound之間的差異前面已經有所展示。在其他方面,兩者還存在更多的差別。
                首先,就像繪圖案例中展示的那樣,runtime unbound是非侵入的。runtime unbound不要求類型繼承自同一類型,只需將類型同concept關聯起來便可。
                其次,concept不是一種局限于OO的技術,不僅涉及成員函數,還包括了自由函數,范圍更廣,更加靈活。
                最后,實現上,Runtime Unbound和Runtime Bound之間有驚人的相似之處。兩者都采用一個函數指針表作為操作分派;都采用一個指向函數表的指針作為入口;一個動態對象上的concept之間的轉 換,也同動多態對象一樣,在不同的函數表間切換。他們唯一的不同,是實現接口的機制。
                動多態用類型兼任接口,通過繼承和虛函數實現接口的功能。用類型作為類型的接口,使得這兩個本來獨立的概念交織在一起。增加整個類型體系的復雜度和耦合度。    concept則利用獨立的系統描述、表達和管理接口。類型則回歸到表達業務對象的功能上來。
                動多態在使用類型表達接口的時候,便很容易地引入一個麻煩的問題,表達功能的類型和表達接口的類型混合在一起,使用時必須通過一些方法區分出哪些是接口, 哪些是功能類型。這增加了對象模型的復雜性。而concept則獨立于類型體系之外,所有對接口的操作都是單一的,檢索和匹配來得更加方便快捷。
                作為繼承體系的基礎部分,動多態的抽象接口必須在繼承結構的最頂端。那么這些抽象類型必須先于其他類型出現。這對系統的早期設計產生很大的壓力,往往一個基礎抽象接口設計有誤,便會造成整個體系的變更。
                而concept是獨立于類型的,那么任何時候都可以將一個類型同接口綁定。接口甚至可以在類型體系基本建立之后才確定。這種靈活性對復雜軟件的開發至關重要,去掉了長期以來套在人們頭上的枷鎖。
                前面已經提到,在不需要concept轉換的情況下,無需執行運行時的concept匹配,所有的調用具有同動多態一樣的效率(都是間接調用)。在執行 concept轉換時,無需象動多態那樣在復雜的繼承體系上檢索,只需執行concept表的hash匹配,效率反而更高,而且更簡單。考慮到這些情況, 我們可以認為concept化的Runtime Unbound多態完全能夠替代傳統的動多態。也就是說,我們不再需要動多態了
                 想象一下,如果一門語言能夠擁有運行時concept,那么它完全可以只保留Static Unbound和Runtime Unbound多態,而放棄Runtime Bound多態。一旦放棄動多態(沒有了虛函數和虛表),那么對象模型便可以大大簡化。所有對象只需要線性分布,基類和成員依次堆疊在一起,也沒有 vtable的干擾,對象結構可以做到最簡單。同時,繼承也回歸了代碼重用的傳統用途。而且,對象獨立于接口存儲,在能夠在編譯時靜態鏈接的時候,可以作 為靜態對象使用。而在需要動態對象的地方,又可以很容易地轉換成動態對象,只需要為其附上concept表和ctable。一切都簡化了。對象模型也更加 容易統一。
                這對于很多底層開發的程序員對于c++復雜而又混亂的對象模型難以接受。如果能夠廢除虛函數,簡化對象模型,那么對于這些底層開發而言,將會帶來直接的好 處。只要確保不使用concpt定義對象、實例化模板,便可以使整個軟件執行Static Unbound。這相當于去掉OOP的C++。否則,就啟用Runtime Unbound,實現運行時多態。

            總結

                Static Unbound和Runtime Unbound作為一對親密無間的多態技術,體現了最完善的抽象形式。兩者各踞一方,相互補充,相互支援。而且兩者具有統一的表現形式,大大方便了使用, 對于軟件工程具有非凡的意義。另一方面,Runtime Bound多態作為OO時代的產物,體現了靜態類型語言在運行時多態方面的最大努力。但是,隨著運行時concept的引入,Runtime Unbound多態自身存在的靜態類型安全問題和性能問題,都能夠得到很好的解決。至此,Runtime Unbound便具備了替代Runtime Bound的實力。相信在不久的將來,Runtime Bound將會逐漸步入它的黃昏。

            參考

            1. http://groups.google.com/group/pongba/web/Runtime+Polymorphic+Generic +Programming.pdf。大牛人Jaakko Järvi等寫的關于Runtime concept的文章,講解了runtime concept的概念的實現方法,并在ConceptC++上以庫的形式實現。其中使用傳統的動多態實現runtime concept,這表明動多態的實現機制同runtime concept是一致的。當然庫的實現很復雜,這是“螺螄殼里做道場”,無奈之舉。Runtime concept還是應當在語言中first-class地實現。
            2. http://www.lubomir.org/academic/MinimizingCodeBloat.pdf。也是Jaakko Järvi寫的,運行時分派的文章。
            3. http://opensource.adobe.com/wiki/index.php/Runtime_Concepts。
            4. Inside C++ Object Model。

            附錄 Runtime Concept的具體實現

                我們有一個concept:
                concept Shape<T>
                {
                    void T::load(xml);
                    void T::draw(device);
                    void move(T&);
                }
                另外,還有一個代表圓的concept:
                concept Cycles<T> :
                    CopyConstructable<T>,
                    Assignable<T>,
                    Swappable<T>,
                    Shape<T>
                {
                    T::T(double, double, double);
                    double T::getX();
                    double T::getY();
                    double T::getR();
                    void T::setX(double);
                    void T::setY(double);
                    void T::setR(double);
                }
                現在有類型Cycle:
                class Cycle
                {
                public:
                    Cycle(double x, double y, double r);
                    Cycle(Cycle const& c);
                    Cycle& operator=(Cycle const& c);
                    void swap(Cycle const& c);
                    void load(xml init);
                    void draw(device dev);
                    double getX();
                    double getY();
                    double getR();
                    void setX(double x);
                    void setY(double y);
                    void setR(double r);
                private:
                    ...
                };
                當定義一個動態對象:
                Shape g=Cycle();
                便會形成如下圖的結構:

                g實際上是一個指針,指向concept表的Shape項,而Shape項指向Shape對應的ctable。由于Cycle refine自Shape等眾多concept,那么Cycle的ctable實際上包含了這些concept的ctable,所以只需一個Cycle的 ctable,而其他concept都分別指向其中各自相應的部分。ctable中的每一個項則指向具體的函數體。
                如果遇到語句:
                Swappable h=concept_cast<Swappable>(g);
                那么,將會執行一個搜索,用concept Swappable的id(比如hash碼)在concept表中檢索是否存在Swappable項。如果存在,就將對應項的指針賦給h。這種操作同 dynamic_cast操作非常相似,只是相比在復雜的對象結構中查詢更加簡單迅速。
                concept表置于對象的頭部或尾部,這是為了便于對象檢索concept接口。每個類型的ctable只需一份。
                對象本體可以很容易地同concept表分離,在完全靜態的情況下,concept表是不需要的。如果需要runtime多態,加上concept表即可。

            posted on 2007-12-06 17:20 longshanks 閱讀(4230) 評論(12)  編輯 收藏 引用

            Feedback

            # re: OOP的黃昏 2007-12-06 18:05 LOGOS
            concept真是好東西啊
            不過這個語言級的新特性,還要等兩年啊  回復  更多評論
              

            # re: OOP的黃昏 2007-12-06 20:14 jfish
            偶的C++功力太淺,這么高級的東西,收藏了慢慢研究,呵呵,concept確實不錯  回復  更多評論
              

            # re: OOP的黃昏 2007-12-06 22:16 萬連文
            物極必反,或許我老了。  回復  更多評論
              

            # re: OOP的黃昏 2007-12-07 10:28 夢在天涯
            oop本身有虛函數和重載,我們就可以認為是運行時多態和編譯時多態。

            后來高手又使用template和template的特化,整出一個編譯時多態。

            上面的這2個倒是還好理解,現在有真個。。。多態

            要用concept來實現,但是我看concept的作用其實就是一個接口,一個抽象。(感覺跟以前沒有什么大的差別哦,也許是我沒有仔細看哦!希望高手過來指點哦)  回復  更多評論
              

            # re: OOP的黃昏 2007-12-07 15:21 abware
            相對于接口來說,Concept提供了另一個維度的抽象方法,不過效果如何有待檢驗。
              回復  更多評論
              

            # re: OOP的黃昏[未登錄] 2007-12-07 18:31 hdqqq
            標題取的和內容沒啥聯系。看了標題跑進來,原來在將concept。  回復  更多評論
              

            # re: OOP的黃昏 2007-12-10 00:02 評價名人自然只能匿了...
            說實在的, pongba僅僅是個技術宣傳者, 而云風則過于偏執, 說實在的, 懂得東西很多, 核心思想很菜, 他倆說的話, 那么一聽就算了...  回復  更多評論
              

            # re: OOP的黃昏 2007-12-11 15:17 dananhai
            受教了,不錯不錯啊  回復  更多評論
              

            # re: OOP的黃昏 2007-12-19 21:09 ffl
            還是寫的很不錯的,OOP沒不會死掉啦
            不過我希望lambda特性能被加入
            boost  回復  更多評論
              

            # re: OOP的黃昏 2008-04-18 16:55 laochai
            偶然看到
            受益匪淺!
            自己模擬了一下
            http://blog.csdn.net/cchhope/archive/2008/04/18/2304969.aspx  回復  更多評論
              

            # re: OOP的黃昏[未登錄] 2008-08-07 12:14 a
            成長中的C++  回復  更多評論
              

            # re: OOP的黃昏 2012-05-24 21:27 Richard Wei
            在C++11中沒有看到concept, 不知博主有啥看法?  回復  更多評論
              

            色8激情欧美成人久久综合电| 久久水蜜桃亚洲av无码精品麻豆| 77777亚洲午夜久久多喷| 2020久久精品国产免费| 久久91精品综合国产首页| 亚洲国产精品无码久久久久久曰 | 久久影视综合亚洲| 亚洲午夜无码久久久久小说| 无码久久精品国产亚洲Av影片| 久久99国产亚洲高清观看首页| 久久综合色之久久综合| 精品久久久无码21p发布| 一本久久a久久精品综合夜夜 | 五月丁香综合激情六月久久| 高清免费久久午夜精品| 久久频这里精品99香蕉久| 久久99国产精品99久久| 欧美喷潮久久久XXXXx| 久久伊人五月天论坛| 久久综合久久综合久久| 亚洲国产精品无码久久98| 热RE99久久精品国产66热| 久久国产免费观看精品| 久久99精品久久久久久动态图| 手机看片久久高清国产日韩| 久久香蕉国产线看观看99| 色偷偷久久一区二区三区| 少妇久久久久久被弄到高潮| 久久精品国产一区二区三区| 久久777国产线看观看精品| 国产三级久久久精品麻豆三级| 久久精品国产2020| 久久精品人妻一区二区三区| 成人亚洲欧美久久久久| 91精品无码久久久久久五月天| 久久国产一区二区| 国产精品久久久久久影院| 久久综合狠狠综合久久综合88| 精品久久久无码21p发布| 亚洲va中文字幕无码久久不卡| 国产一区二区久久久|