青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

longshanks

  C++博客 :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
  14 Posts :: 0 Stories :: 214 Comments :: 0 Trackbacks

常用鏈接

留言簿(10)

我參與的團(tuán)隊(duì)

搜索

  •  

最新評(píng)論

閱讀排行榜

評(píng)論排行榜


GP技術(shù)的展望——道生一,一生二

by  莫華楓



    長(zhǎng)期以來(lái),我們始終把GP(泛型編程)作為一種輔助技術(shù),用于簡(jiǎn)化代碼結(jié)構(gòu)、提高開(kāi)發(fā)效率。從某種程度上來(lái)講,這種觀念是對(duì)的。因?yàn)槠駷橹梗珿P技術(shù)還只是一種編譯期技術(shù)。只能在編譯期發(fā)揮作用,一旦軟件完成編譯,成為可執(zhí)行代碼,便失去了利用GP的機(jī)會(huì)。對(duì)于現(xiàn)在的多數(shù)應(yīng)用而言,運(yùn)行時(shí)的多態(tài)能力顯得尤為重要。而現(xiàn)有的GP無(wú)法在這個(gè)層面發(fā)揮作用,以至于我這個(gè)“GP迷”也不得不灰溜溜地聲稱(chēng)“用OOP構(gòu)建系統(tǒng),用GP優(yōu)化代碼”。

    然而,不久前,在TopLanguage group上的一次討論,促使我們注意到runtime GP這個(gè)概念。從中,我們看到了希望——使GP runtime化的希望——使得GP有望在運(yùn)行時(shí)發(fā)揮其巨大的威力,進(jìn)一步為軟件的設(shè)計(jì)與開(kāi)發(fā)帶來(lái)更高的效率和更靈活的結(jié)構(gòu)。
    在這個(gè)新的系列文章中,我試圖運(yùn)用runtime GP實(shí)現(xiàn)一些簡(jiǎn)單,但典型的案例,來(lái)檢測(cè)runtime GP的能力和限制,同時(shí)也可以進(jìn)一步探討和展示這種技術(shù)的特性。

運(yùn)行時(shí)多態(tài)

    現(xiàn)在的應(yīng)用側(cè)重于交互式的運(yùn)作形式,要求軟件在用戶(hù)輸入下作出響應(yīng)。為了在這種情況下,軟件的整體結(jié)構(gòu)的優(yōu)化,大量使用組件技術(shù),使得軟件成為“可組裝” 的系統(tǒng)。而接口-實(shí)現(xiàn)分離的結(jié)構(gòu)形式很好地實(shí)現(xiàn)了這個(gè)目標(biāo)。多態(tài)在此中起到了關(guān)鍵性的作用。其中,以O(shè)OP為代表的“動(dòng)多態(tài)”(也稱(chēng)為 “subtyping多態(tài)”),構(gòu)建起在運(yùn)行時(shí)可調(diào)控的可組裝系統(tǒng)。GP作為“靜多態(tài)”,運(yùn)用泛化的類(lèi)型體系,大大簡(jiǎn)化這種系統(tǒng)的構(gòu)建,消除重復(fù)勞動(dòng)。另外還有一種鮮為人知的多態(tài)形式,被《C++ Template》的作者David Vandevoorde和Nicolai M. Josuttis稱(chēng)為runtime unbound多態(tài)。而原來(lái)的“動(dòng)多態(tài)”,即OOP多態(tài),被細(xì)化為runtime bound多態(tài);“靜多態(tài)”,也就是模板,則被稱(chēng)為static unbound多態(tài)。
    不過(guò)這種稱(chēng)謂容易引起誤解,主要就是unbound這個(gè)詞上。在這里unbound和bound是指在編寫(xiě)代碼時(shí),一個(gè)symbol是否同一個(gè)具體的類(lèi)型 bound。從這點(diǎn)來(lái)看,由于GP代碼在編寫(xiě)之時(shí),面向的是泛型,不是具體的類(lèi)型,那么GP是unbound的。因?yàn)楝F(xiàn)有的GP是編譯期的技術(shù),所以是 static的。OOP的動(dòng)多態(tài)則必須針對(duì)一個(gè)具體的類(lèi)型編寫(xiě)代碼,所以是bound的。但因?yàn)閯?dòng)多態(tài)可以在運(yùn)行時(shí)確定真正的類(lèi)型,所以是runtime 的。至于runtime unbound,以往只出現(xiàn)在動(dòng)態(tài)語(yǔ)言中,比如SmallTalk、Python、Ruby,一種形象地稱(chēng)謂是“duck-typing”多態(tài)。關(guān)于多態(tài)的更完整的分類(lèi)和介紹可以看這里
    通過(guò)動(dòng)態(tài)語(yǔ)言機(jī)制實(shí)現(xiàn)的runtime unbound,存在的性能和類(lèi)型安全問(wèn)題。但當(dāng)我們將GP中的concept技術(shù)推廣到runtime時(shí)會(huì)發(fā)現(xiàn),rungime unbound可以擁有同OOP動(dòng)多態(tài)相當(dāng)?shù)男屎皖?lèi)型安全性,但卻具有更大的靈活性和更豐富的特性。關(guān)于這方面,我已經(jīng)寫(xiě)過(guò)一篇文章 ,大致描述了一種實(shí)現(xiàn)runtime concept的途徑(本文的附錄里,我也給出了這種runtime concept實(shí)現(xiàn)的改進(jìn))。

Runtime Concept

    Runtime concept的實(shí)現(xiàn)并不會(huì)很復(fù)雜,基本上可以沿用OOP中的“虛表”技術(shù),并且可以更加簡(jiǎn)單。真正復(fù)雜的部分是如何在語(yǔ)言層面表達(dá)出這種runtime GP,而不對(duì)已有的static GP和其他語(yǔ)言特性造成干擾。在這里,我首先建立一個(gè)基本的方案,然后通過(guò)一些案例對(duì)其進(jìn)行檢驗(yàn),在發(fā)現(xiàn)問(wèn)題后再做調(diào)整。
    考慮到runtime concept本身也是concept,那么沿用static concept的定義形式是不會(huì)有問(wèn)題的:
      concept myconcept<T> {
          T& copy(T& lhs, T const& rhs);
          void T::fun();
          ...
      }
    具體的concept定義和使用規(guī)則,可以參考C++0x的concept提案這篇文章 ,以及這篇文章
    另一方面,我們可以通過(guò)concept_map將符合一個(gè)concept的類(lèi)型綁定到該concept之上:
      concept_map myconcept<MyType> {}
    相關(guān)內(nèi)容也可參考上述文件。
    有了concept之后,我們便可以用它們約束一個(gè)模板:
      template<myconcept T>void myfun(T const& val); //函數(shù)模板
      template<myconcept T>class X  //類(lèi)模板
      {
           ...
      };
    到此為止,runtime concept同static concept還是同一個(gè)事物。它們真正的分離在于使用。對(duì)于static concept應(yīng)用,我們使用一個(gè)具體的類(lèi)型在實(shí)例化(特化)一個(gè)模板:
      X<MyType> x1;  //實(shí)例化一個(gè)類(lèi)模板
      MyType obj1;
      myfun(obj1);  //編譯器推導(dǎo)obj1對(duì)象的類(lèi)型實(shí)例化函數(shù)模板
      myfun<MyType>(obj1);  //函數(shù)模板的顯式實(shí)例化
    現(xiàn)在,我們將允許一種非常規(guī)的做法,以使runtime concept成為可能:允許使用concept實(shí)例化一個(gè)模板,或定義一個(gè)對(duì)象
      X<myconcept> x2;
      myconcept* obj2=new myconcept<MyType>;
      myfun(obj2);  //此處,編譯器將會(huì)生成runtime版本的myfun
    這里的含義非常明確:對(duì)于x2,接受任何符合myconcept的類(lèi)型的對(duì)象。obj2是一個(gè)“動(dòng)態(tài)對(duì)象”(這里將runtime concept引入的那種不知道真實(shí)類(lèi)型,但符合某個(gè)concept的對(duì)象稱(chēng)為“動(dòng)態(tài)對(duì)象”。而類(lèi)型明確已知的對(duì)象成為“靜態(tài)對(duì)象”),符合myconcept要求。至于實(shí)際的類(lèi)型,隨便,只要符合myconcept就行。
    這種情形非常類(lèi)似于傳統(tǒng)動(dòng)多態(tài)的interface。但是,它們有著根本的差異。interface是一個(gè)具體的類(lèi)型,并且要求類(lèi)型通過(guò)繼承這種形式實(shí)現(xiàn)這個(gè)接口。而concept則不是一種類(lèi)型,而是一種“泛型”——具備某種特征的類(lèi)型的抽象(或集合),不需要在類(lèi)型創(chuàng)建時(shí)立刻與接口綁定。與 concept的綁定(concept_map)可以發(fā)生在任何時(shí)候。于是,runtime concept實(shí)際上成為了一種非侵入的接口。相比interface這種侵入型的接口,更加靈活便捷。
    通過(guò)這樣一種做法,我們便可以獲得一種能夠在運(yùn)行時(shí)工作的GP系統(tǒng)。
    在此基礎(chǔ)上,為了便于后續(xù)案例展開(kāi),進(jìn)一步引入一些有用的特性:
  1. 一個(gè)concept的assosiate type被視為一個(gè)concept。一個(gè)concept的指針/引用(concept_id*/concept_id&,含義是指向一個(gè)符合concept_id的動(dòng)態(tài)對(duì)象,其實(shí)際類(lèi)型未知),都被視作concept。一個(gè)類(lèi)模板用concept實(shí)例化后,邏輯上也是一個(gè)concept。
  2. 動(dòng)態(tài)對(duì)象的創(chuàng)建。如果需要在棧上創(chuàng)建動(dòng)態(tài)對(duì)象,那么可以使用語(yǔ)法:concept_id<type_id> obj_id; 這里concept_id是concept名,type_id是具體的類(lèi)型名,obj_id是對(duì)象名稱(chēng)。這樣,便在棧上創(chuàng)建了一個(gè)符合concept_id的動(dòng)態(tài)對(duì)象,其實(shí)際類(lèi)型是type_id
    如果需要在堆上創(chuàng)建動(dòng)態(tài)對(duì)象,那么可以用語(yǔ)法:concept_id* obj_id=new concept_id<type_id>; 這實(shí)際上可以看作“concept指針/引用”。
  3. concept推導(dǎo)(編譯期)。對(duì)于表達(dá)式concept_id obj_id=Exp,其中Exp是一個(gè)表達(dá)式,如果表達(dá)式Exp的類(lèi)型是具體的類(lèi)型,那么obj_id代表了一個(gè)靜態(tài)對(duì)象,其類(lèi)型為Exp的類(lèi)型。如果表達(dá)式Exp的類(lèi)型是concept,那么obj_id是一個(gè)動(dòng)態(tài)對(duì)象,其類(lèi)型為Exp所代表的concept。
    那么如何確定Exp是具體類(lèi)型還是concept?可以使用這么一個(gè)規(guī)則:如果Exp中涉及的對(duì)象,比如函數(shù)的實(shí)參、表達(dá)式的操作數(shù)等等,只要有一個(gè)是動(dòng)態(tài)對(duì)象(類(lèi)型是concept),那么Exp的類(lèi)型就是concept;反之,如果所有涉及的對(duì)象都是靜態(tài)對(duì)象(類(lèi)型為具體的類(lèi)型),那么Exp的類(lèi)型為相應(yīng)的具體類(lèi)型。同樣的規(guī)則適用于concept*或concept&。
  4. concept轉(zhuǎn)換。類(lèi)似在類(lèi)的繼承結(jié)構(gòu)上執(zhí)行轉(zhuǎn)換。refined concept可以隱式地轉(zhuǎn)換成base concept,反過(guò)來(lái)必須顯式地進(jìn)行,并且通過(guò)concept_cast操作符執(zhí)行。兄弟concept之間也必須通過(guò)concept_cast轉(zhuǎn)換。
  5. 基于concept的重載,也可以在runtime時(shí)執(zhí)行,實(shí)現(xiàn)泛化的dynamic-dispatch操作。

    下面,就開(kāi)始第一個(gè)案例。

案例:升級(jí)的坦克

    假設(shè)我們做一個(gè)游戲,主題是開(kāi)坦克打仗。按游戲的慣例,消滅敵人可以得到積分,積分到一定數(shù)量,便可以升級(jí)。為了簡(jiǎn)便起見(jiàn),我們只考慮對(duì)主炮升級(jí)。第一級(jí)的主炮是90mm的;第二級(jí)的主炮升級(jí)到120mm。主炮分兩種,一種只能發(fā)射穿甲彈,另一種只能發(fā)射高爆彈。因此,坦克也分為兩種:能打穿甲彈的和能打高爆彈的。
    為了使代碼容易開(kāi)發(fā)和維護(hù),我們考慮采用模塊化的方式:開(kāi)發(fā)一個(gè)坦克的框架,然后通過(guò)更換不同的主炮,實(shí)現(xiàn)不同種類(lèi)的坦克和升級(jí):
      //一些基本的concept定義
      //炮彈頭concept
      concept Warheads<typename T> {
          double explode(TargetType tt); //炮彈爆炸,返回殺傷率。不同彈頭,對(duì)不同類(lèi)型目標(biāo)殺傷率不一樣。
      }
      //炮彈concept,我們關(guān)心的當(dāng)然是彈頭,所以用Warheads定義一個(gè)associate type
      concept Rounds<typename T> {
          Warheads WH;
          ...
      }
      //主炮concept
      concept Cannons<typename T> {
          Rounds R;
          void T::load(R& r); //裝填炮彈,load之后炮彈會(huì)存放在炮膛里,不能再load,除非把炮彈打出去
          R::WH T::fire();   //開(kāi)炮,返回彈頭。發(fā)射后炮膛變空,可以再load
      }
      //類(lèi)型和模板定義
      //坦克類(lèi)模板
      template<Cannons C>
      class Tank
      {
          ...
      public:
          void load(typenam C::R& r) {
              m_cannon.load(r);
          }
          typename C::R::WH fire() {
              return m_cannon.fire();
          }
      private:
          C m_cannon;
      };
      //主炮類(lèi)模板
      template<Rounds Rd>
      class Cannon
      {
      public:
          typedef Rd R;
          void load(R& r) {...}
          typename R::WH fire() {...}
      }
      template<Rounds Rd> concept_map Cannons<Cannon<Rd>>{}
      //炮彈類(lèi)模板
      template<Warheads W>
      class Round
      {
      public:
          typedef W WH;
          static const int caliber=W::caliber;
          W shoot() {...}
          ...
      };
      template<Warhead W> concept_map<Round<W>>{}
      //彈頭類(lèi)模板,通過(guò)traits把各類(lèi)彈頭的不同行為彈頭的代碼框架分離,使類(lèi)型“可組裝”
      concept WH_Traits<T> {
          return T::exploed(int, TargetType, double, Material);
      }
      template<WH_Traits wht, int c>
      class Warhead
      {
      public:
          const static int caliber=c;
          double explode(TargetType tt) {
              return wht::exploed(c, tt, ...);
          }
          ...
      };
      template<WH_Traits WHT, int c> concept_map<Warhead<WHT, c>>{}
      //彈頭traits
      struct KE_WHTraits
      {
          static double exploed(int caliber, TargetType tt, double weight, Material m) {...}
      };
      concept_map<KE_WHTraits>{}
      struct HE_WHTraits
      {
          static double exploed(int caliber, TargetType tt, double weight, Material m) {...}
      };
      concept_map<HE_WHTraits>{}
      //定義各類(lèi)彈頭
      typedef Warhead<KE_WHTraits, 90> WH_KE_90;
      typedef Warhead<KE_WHTraits, 120> WH_KE_120;
      typedef Warhead<HE_WHTraits, 90> WH_HE_90;
      typedef Warhead<HE_WHTraits, 120> WH_HE_120;
      //定義各類(lèi)炮彈
      typedef Round<WH_KE_90> Round_KE_90;
      typedef Round<WH_KE_120> Round_KE_120;
      typedef Round<WH_HE_90> Round_HE_90;
      typedef Round<WH_HE_120> Round_HE_120;
      //定義各類(lèi)主炮
      typedef Cannon<Round_KE_90> Cannon_KE_90;
      typedef Cannon<Round_KE_120> Cannon_KE_120;
      typedef Cannon<Round_HE_90> Cannon_HE_90;
      typedef Cannon<Round_HE_120> Cannon_HE_120;
      //定義各類(lèi)坦克
      typedef Tank<Cannon_KE_90> Tank_KE_90;
      typedef Tank<Cannon_KE_120> Tank_KE_120;
      typedef Tank<Cannon_HE_90> Tank_HE_90;
      typedef Tank<Cannon_HE_120> Tank_HE_120;
    于是,當(dāng)我們開(kāi)始游戲時(shí),就可以按照玩家的級(jí)別創(chuàng)建坦克對(duì)象,并且射擊:
      //第一級(jí)玩家,駕駛發(fā)射90mm高爆炮彈的坦克
      Tank_HE_90 myTank;
      Round_HE_90 r1;
      myTank.load(r1);
      myTank.fire();
      //第二級(jí)玩家,駕駛發(fā)射120mm穿甲彈的坦克
      Tank_KE_120 yourTank;
      Round_KE_120 r2;
      yourTank.load(r2);
      yourTank.fire();
      //如果這樣,危險(xiǎn),炮彈不匹配,小心炸膛
      myTank.load(r2); //error
    到目前為止,這些代碼僅僅展示了靜態(tài)的GP。concept在這里也只是起到了類(lèi)型參數(shù)約束的作用。但是,在這些代碼中,我們可以明顯地看到,在運(yùn)用GP 的參數(shù)化類(lèi)型特性之后,可以很容易地進(jìn)行組件化。對(duì)于一組具備類(lèi)似行為和結(jié)構(gòu)特征的類(lèi)型,我們可以通過(guò)模板的類(lèi)型參數(shù),將差異部分抽取出來(lái),獨(dú)立成所謂的 “traits”或者“policy”。并且通過(guò)traits或policy的組合構(gòu)成不同的產(chǎn)品。在某些復(fù)雜的情況下,traits和policy還可以進(jìn)一步通過(guò)traits或policy實(shí)現(xiàn)組件化。
    接下來(lái),很自然地應(yīng)當(dāng)展開(kāi)runtime GP的運(yùn)用了。
    一個(gè)游戲者是可以升級(jí)的,為了使得這種升級(jí)變得更加靈活,我們會(huì)很自然地使用Composite模式。現(xiàn)在,我們可以在Runtime concept的支援下實(shí)現(xiàn)GP版的Composite模式:
      //坦克的concept
      concept tanks<T> {
          typename Round;
          void T::load(Round&);
          Round::WH T::fire();
      }
      concept_map tanks<Tank_KE_90>{}
      concept_map tanks<Tank_HE_90>{}
      concept_map tanks<Tank_KE_120>{}
      concept_map tanks<Tank_HE_120>{}
      //坦克構(gòu)造函數(shù)模板
      template<tanks T>
      T* CreateTank(WHType type, int level) { //WHType是一個(gè)枚舉表明炮彈種類(lèi)
          switch(level)
          {
          case 1:
              if(type==wht_KE)
                  return new tanks<Tank_KE_90>;
              else
                  return new tanks<Tank_HE_90>;
          case 2:
              if(type==wht_KE)
                  return new tanks<Tank_KE_120>;
              else
                  return new tanks<Tank_HE_120>;
          default:
              throw error("no such tank.");
          }
      }
      //玩家類(lèi)
      class player
      {
      public:
          void update() {
m_pTank=CreateTank(m_tankType, ++m_level);
          }
          ...
      private:
          int m_level;
          WHType m_tankType;
tanks* m_pTank;
      };
    在類(lèi)player中,使用了一個(gè)concept,而不是一個(gè)類(lèi)型,來(lái)定義一個(gè)對(duì)象。根據(jù)前面提到的concept推導(dǎo)規(guī)則,m_pTank指向一個(gè)動(dòng)態(tài)對(duì)象,還是靜態(tài)對(duì)象,取決于為它賦值的表達(dá)式類(lèi)型是concept還是具體類(lèi)型。在update()函數(shù)中,可以看到,m_pTank通過(guò)表達(dá)式CreateTank(m_tankType, ++m_level)賦值。那么這個(gè)函數(shù)的返回類(lèi)型,將決定m_pTank的類(lèi)型。CreateTank()是一個(gè)模板,返回類(lèi)型是模板參數(shù),并且是符合concept tanks的類(lèi)型。關(guān)鍵在于代碼中的return new tanks<...>語(yǔ)句。前文已經(jīng)說(shuō)過(guò),這種形式是使用<...>中的類(lèi)型創(chuàng)建一個(gè)符合tanks的動(dòng)態(tài)對(duì)象。所以,CreateTank()返回的是動(dòng)態(tài)對(duì)象。那么,m_pTank也將指向一個(gè)動(dòng)態(tài)對(duì)象。在運(yùn)行時(shí),當(dāng)玩家達(dá)到一定條件,便可以升級(jí)。update()成員函數(shù)將根據(jù)玩家的級(jí)別重新創(chuàng)建相應(yīng)的坦克對(duì)象,賦值到m_pTank中。
    這里,實(shí)際上是利用tanks這個(gè)concept描述,充當(dāng)類(lèi)型的公有接口。它所具有的特性同動(dòng)多態(tài)的抽象基類(lèi)是非常相似的。但是所不同的是,如同我在代碼中展現(xiàn)的那樣,concept作為接口,可以在任何時(shí)候定義,同類(lèi)型綁定。而無(wú)需象抽象基類(lèi)那樣,必須在類(lèi)型定義之前定義。于是,這種非侵入式的接口相比抽象基類(lèi)擁有更加靈活自由的特性。
    然而,事情還沒(méi)有完。在進(jìn)一步深化坦克案例后,我們還將發(fā)現(xiàn)runtime GP擁有更加有趣和重要的特性。
    坦克開(kāi)炮為的是攻擊目標(biāo)。對(duì)目標(biāo)的毀傷情況直接關(guān)系到玩家的生存和得分。所以,我們必須對(duì)射擊后,目標(biāo)的損毀情況進(jìn)行計(jì)算。于是編寫(xiě)了這樣一組函數(shù):
      double LethalityEvaluate(Target& t, double hitRate, WH_KE_90& wh) {...}
      double LethalityEvaluate(Target& t, double hitRate, WH_HE_90& wh) {...}
      double LethalityEvaluate(Target& t, double hitRate, WH_KE_120& wh) {...}
      double LethalityEvaluate(Target& t, double hitRate, WH_HE_120& wh) {...}
    Target是目標(biāo);hitRate是命中率,根據(jù)坦克和目標(biāo)的位置、射擊參數(shù)綜合計(jì)算獲得(如果想要更真實(shí),可以加上風(fēng)向、風(fēng)力、氣溫、濕度、海拔等等因素);wh就是發(fā)射出來(lái)的炮彈了。函數(shù)返回殺傷率。如此,我們便可以在射擊之后進(jìn)行評(píng)估了:
      double l=LethalityEvaluate(house, hr, myTank.fire());
     現(xiàn)在,游戲需要進(jìn)行一些擴(kuò)展,增加一個(gè)升級(jí),允許坦克升級(jí)到第三級(jí)。到了第三極,主炮的口徑就升到頭了,但可以升級(jí)功能,可以發(fā)射穿甲彈和高爆彈。這樣,我們就需要一個(gè)“兩用”的主炮類(lèi)。但是,實(shí)際上并不需要直接做這么一個(gè)類(lèi),只需要用“兩用”的彈藥來(lái)實(shí)例化Cannon模板:
      concept Warheads120<T> : Warheads<T> { //120mm炮彈頭concept
          double LethalityEvaluate(Target& t, double hitRate, T& wh);
      }
      concept Rounds120<T> : Rounds<T> {}
      concept_map Warheads120<WH_KE_120> {}  //120mm的穿甲彈屬于Warheads120
      concept_map Warheads120<WH_HE_120> {}  //120mm的高爆彈屬于Warheads120
      template<WH120 WH> concept_map Rounds120<Round<WH>> {} //所有彈頭是Warheads120的炮彈都是屬于Rounds120
      typedef Canon<Rounds120> Cannon120; //用Rounds120實(shí)例化Cannon模板,得到“兩用”主炮
    一堆炫目的concept和concept_map之后,得到Rounds120,就是所謂的“兩用”彈藥。作為一個(gè)concept,它同兩種類(lèi)型map 在一起,實(shí)際上就成了這兩個(gè)類(lèi)型的接口。當(dāng)我們使用Rounds120實(shí)例化Cannon<>模板時(shí),也就創(chuàng)建了一個(gè)“兩用的主炮”(使用 Rounds120彈藥的主炮)。如果用這個(gè)Cannon120實(shí)例化Tank模板,那么就可以得到第三級(jí)坦克(裝上Cannon120主炮的坦克就是第三級(jí)):
      typedef Tank<Cannon120> TankL3;
    于是,我們可以使用不同的120mm彈藥裝填主炮,并且發(fā)射相應(yīng)的炮彈:
      TankL3 tank_l3;
      Round_KE_120 ke_round;  //創(chuàng)建一枚穿甲彈
      Round_HE_120 he_round;  //創(chuàng)建一枚高爆彈
      tank_l3.load(ke_round);  //裝填穿甲彈
      tank_l3.fire();               //發(fā)射穿甲彈
      tank_l3.load(he_round);  //裝填高爆彈
      tank_l3.fire();               //發(fā)射高爆彈
    現(xiàn)在,我們把注意力從消滅敵人,轉(zhuǎn)移到TankL3::load()的參數(shù)類(lèi)型和TankL3::fire()的返回類(lèi)型上。在一級(jí)和二級(jí)坦克(類(lèi)型 Tank_KE_90等)上,load()成員的參數(shù)類(lèi)型是Round_KE_90等具體的類(lèi)型;而fire()的返回類(lèi)型亦是如此。但TankL3是用 Cannon120實(shí)例化的,而Cannon120是用Rounds120這個(gè)concept實(shí)例化的。根據(jù)Tank<>模板的定義, load()成員的參數(shù)類(lèi)型實(shí)際上是模板參數(shù)上的一個(gè)associate type。而這個(gè)associate type實(shí)際上就是Rounds120。這意味著load()實(shí)例化后的簽名是:void load(Rounds120& r)(這里暫且允許concept作為類(lèi)型參數(shù)使用)。只要符合Rounds120的類(lèi)型都可以作為實(shí)參傳遞給load()成員。同樣,fire()成員的返回類(lèi)型來(lái)自于Round120上的associate type,也是個(gè)concept。因此,fire()實(shí)例化后的簽名是:Warheads120 fire()。
    接下來(lái)值得注意的是fire()成員。它返回類(lèi)型是一個(gè)concept,那么返回的將是一個(gè)動(dòng)態(tài)對(duì)象。在運(yùn)行時(shí),它可能返回WH_KE_120的實(shí)例,也可能返回WH_HE_120的實(shí)例,取決于運(yùn)行時(shí)load()函數(shù)所裝填的炮彈類(lèi)型。當(dāng)我們采用LethalityEvaluate()函數(shù)對(duì)該炮彈的殺傷情況進(jìn)行評(píng)估將會(huì)出現(xiàn)比較微妙的情況:
      double x=LethalityEvaluate(hisTank, hr, tank_l3.fire());
    這時(shí)候,編譯器應(yīng)當(dāng)選擇哪個(gè)LethalityEvaluate()?由于tank_l3.fire()返回的是一個(gè)動(dòng)態(tài)對(duì)象,具體的類(lèi)型編譯時(shí)不知道。實(shí)際上,在正宗的靜態(tài)語(yǔ)言中,這樣的調(diào)用根本無(wú)法通過(guò)編譯。當(dāng)然,編譯器可以通過(guò)runtime reflect獲得類(lèi)型信息,然后在LethalityEvaluate()的重載中匹配正確的函數(shù)。然而,這種動(dòng)態(tài)語(yǔ)言做法會(huì)造成性能上的問(wèn)題,為靜態(tài)語(yǔ)言所不屑。
    但是,在這里,在runtime concept的作用下,我們可以使這種調(diào)用成為靜態(tài)的、合法的,并且是高效的。請(qǐng)注意我在concept Warhead120的定義中加入了一個(gè)associate function:double LethalityEvaluate(Target& t, double hitRate, T& wh);。runtime concept會(huì)很忠實(shí)地將concept定義中的associate function構(gòu)造到一個(gè)函數(shù)指針表(我稱(chēng)之為ctable)中。(詳細(xì)情況請(qǐng)看本文附錄和這篇文章的附錄)。因此,與tank_l3.fire()返回的動(dòng)態(tài)對(duì)象實(shí)際類(lèi)型對(duì)應(yīng)的LethalityEvaluate()函數(shù)版本的指針正老老實(shí)實(shí)地躺在相應(yīng)的ctable里。所以,我們可以直接從動(dòng)態(tài)對(duì)象上獲得指向ctable的指針,并且找出相應(yīng)的LethalityEvaluate()函數(shù)指針,然后直接調(diào)用即可。比如:
      tank_l3.load(ke_round);
      double x=LethalityEvaluate(hisTank, hr, tank_l3.fire());
    在這些代碼的背后,ke_round通過(guò)load()裝填入主炮后,便搖身變成了一個(gè)動(dòng)態(tài)對(duì)象。編譯器會(huì)為它附加上指向ctable的指針,然后在調(diào)用 fire()的時(shí)候返回指向這個(gè)動(dòng)態(tài)對(duì)象的引用。此時(shí),編譯器發(fā)現(xiàn)這個(gè)動(dòng)態(tài)對(duì)象所對(duì)應(yīng)的Warhead120 concept上已經(jīng)定義了一個(gè)名為L(zhǎng)ethalityEvaluate()的associate function,并且簽名與當(dāng)前調(diào)用相符。于是,便可以直接找到ctable中LethalityEvaluate()對(duì)應(yīng)的那個(gè)函數(shù)指針,無(wú)所顧忌的調(diào)用。由于一個(gè)concept的associate function肯定是同實(shí)際類(lèi)型匹配的函數(shù)版本。比如,對(duì)于WH_HE_120而言,它的associate function LethalityEvaluate()是版本:double LethalityEvaluate(Target& t, double hitRate, WH_HE_120& wh) {...}。其他版本的LethalityEvaluate()都無(wú)法滿(mǎn)足concept Warhead120施加在類(lèi)型WH_HE_120上的約束。
    這個(gè)特性就使得runtime concept作為接口,相比動(dòng)多態(tài)的抽象接口,具有更大的靈活性。抽象接口只表達(dá)了類(lèi)的成員,以及類(lèi)本身的行為,無(wú)法表達(dá)類(lèi)型同其他類(lèi)型的互動(dòng)關(guān)系,或者說(shuō)類(lèi)型間的交互。而concept同時(shí)描述了成員函數(shù)和相關(guān)的自由函數(shù)(包括操作符),使得類(lèi)型間的關(guān)系也可以通過(guò)接口直接獲得,無(wú)需再通過(guò) reflect等間接的動(dòng)態(tài)手段。
    這一點(diǎn)在處理內(nèi)置類(lèi)型(如int、float)、預(yù)置類(lèi)型(某些庫(kù)中的類(lèi)型)、第三方類(lèi)型等不易或無(wú)法修改的類(lèi)型有至關(guān)重要的作用。在OOP下,我們無(wú)法輸出一個(gè)“整數(shù)”,或許是short、或許是long,甚至是unsinged longlong。為此,我們要么把它們轉(zhuǎn)換成一個(gè)“最基礎(chǔ)類(lèi)型”(C/C++的void*,或C#的Object*),然后運(yùn)用rtti信息進(jìn)行類(lèi)型轉(zhuǎn)換,再做處理;要么使用variant這種類(lèi)型包裝(就像COM中的那樣),然后為他們?nèi)娑x一套計(jì)算庫(kù)。但runtime concept不僅僅允許輸出“整數(shù)”這樣一個(gè)動(dòng)態(tài)對(duì)象,而且還將相關(guān)的各種操作附在動(dòng)態(tài)對(duì)象之上,使之無(wú)需借助rtti或者輔助類(lèi)型也可進(jìn)行各類(lèi)處理,就如同處理具體類(lèi)型的對(duì)象那樣。
    但是,在這里我僅僅考察了針對(duì)一個(gè)類(lèi)型的concept(暫且稱(chēng)之為一元concept),還未涉及兩個(gè)和兩個(gè)以上類(lèi)型的concept(暫且稱(chēng)為多元 concept,或n-元concept)。在實(shí)際開(kāi)發(fā)中,多數(shù)操作都會(huì)涉及多個(gè)對(duì)象,比如兩個(gè)數(shù)相加、一種類(lèi)型轉(zhuǎn)換成另一種。此時(shí),我們將會(huì)面對(duì)多元的 concept。但是多元的runtime concept的特性還不清楚,還需要進(jìn)一步研究分析。

總結(jié)

    本文初步展示了在引入runtime concept之后,GP的動(dòng)態(tài)化特性。歸納起來(lái)有以下幾點(diǎn):
  1. static GP和runtime GP之間在形式上完全統(tǒng)一,兩者可以看作同一種抽象機(jī)制的不同表現(xiàn)。因此,我們?cè)跇?gòu)造類(lèi)型、函數(shù)等代碼實(shí)體的時(shí)候,并不需要考慮它們將來(lái)需要作為static使用,還是runtime使用。static和runtime的控制完全取決于這些代碼實(shí)體的使用方式。這就很好地減少了軟件項(xiàng)目早期設(shè)計(jì),以及庫(kù)設(shè)計(jì)的前瞻性方面壓力。
  2. runtime concept作為非侵入式的接口,可以非常靈活地使用。我們無(wú)需在代碼編寫(xiě)的一開(kāi)始就精確地定義好接口,可以先直接編寫(xiě)功能類(lèi)型,逐步構(gòu)建軟件結(jié)構(gòu)。需要時(shí)再定義接口(concept),并可以在任何時(shí)候與類(lèi)型綁定。接口的定制可以成為一個(gè)逐步推進(jìn)的過(guò)程,早期的接口設(shè)計(jì)不足產(chǎn)生的不良影響相應(yīng)地弱化了。
  3. runtime concept相比動(dòng)多態(tài)的抽象接口更加自由。concept可以對(duì)類(lèi)型的成員函數(shù)、自由函數(shù)、類(lèi)型特征等等方面的特性作出描述。在runtime化之后,相關(guān)自由函數(shù)成為了接口的一部分。更進(jìn)一步規(guī)約了類(lèi)型在整體軟件的代碼環(huán)境中的行為特征。同時(shí),也為動(dòng)態(tài)對(duì)象的訪(fǎng)問(wèn)提供更多的信息和手段。
  4. concept不僅實(shí)現(xiàn)類(lèi)型描述,還可以進(jìn)一步描述類(lèi)型之間的關(guān)系。這大大完善了抽象體系。特別在runtime情況下,這種更寬泛的類(lèi)型描述能力可以起到兩個(gè)作用:其一,進(jìn)一步約束了動(dòng)態(tài)對(duì)象的行為;其二,為外界操作和使用類(lèi)型提供更多的信息,消除或減少了類(lèi)型匹配方面的抽象懲罰。這個(gè)方面的更多特性尚不清楚,還需要更進(jìn)一步地深入研究。
    綜上所述,我們可以看到runtime GP在不損失性能的情況下,具備相比動(dòng)多態(tài)更靈活、更豐富的手段。從根本上而言,以concept為核心的GP提供了更基礎(chǔ)的抽象體系(關(guān)于這方面探討,請(qǐng)看我的這篇文章中關(guān)于concept對(duì)類(lèi)型劃分的作用部分)。或者說(shuō),concept的類(lèi)型描述和約束作用體現(xiàn)了類(lèi)型抽象的本質(zhì),而在此基礎(chǔ)上進(jìn)一步衍生出static和runtime兩種具體的使用方式。這也就是所謂:道生一,一生二。:)

附錄

Runtime Concept實(shí)現(xiàn)方案二

    我在這篇文章附錄里,給出了一種實(shí)現(xiàn)runtime concept的可能方案。這里,我進(jìn)一步對(duì)這個(gè)方案做了一些改進(jìn),使其更加精簡(jiǎn)、高效。
    假設(shè)我們有一個(gè)concept:
    concept Shape<T>
    {
        void T::load(xml);
        void T::draw(device);
        void move(T&);
    }
    另外,還有一個(gè)代表圓的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);
    }
    現(xiàn)在有類(lèi)型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:
        ...
    };
    我們將類(lèi)型Cycle map到concept Cycles上:
      concept_map Cycles<Cycle>{}
    當(dāng)我們創(chuàng)建對(duì)象時(shí),將會(huì)得到如下圖的結(jié)構(gòu):

runtime concept-2

    concept表(concept list)不再同對(duì)象放在一起,而是同一個(gè)類(lèi)型的類(lèi)型信息放在一起。一同放置的還有ctable。ctable中每個(gè)對(duì)應(yīng)的concept項(xiàng)都有一個(gè)指向 concept表的指針(也可以指向類(lèi)型信息頭),用以找到concept list,執(zhí)行concept cast。動(dòng)態(tài)對(duì)象,或動(dòng)態(tài)對(duì)象的引用/指針上只需附加一個(gè)指向相應(yīng)的concept的指針即可。相比前一個(gè)方案,內(nèi)存利用率更高。

posted on 2008-01-06 17:17 longshanks 閱讀(3087) 評(píng)論(7)  編輯 收藏 引用

Feedback

# re: GP技術(shù)的展望&mdash;&mdash;道生一,一生二 2008-01-07 16:00 caoke
瘋了  回復(fù)  更多評(píng)論
  

# re: GP技術(shù)的展望&mdash;&mdash;道生一,一生二[未登錄](méi) 2008-01-11 11:25 duguguiyu
搬個(gè)凳子慢慢看。。。  回復(fù)  更多評(píng)論
  

# re: GP技術(shù)的展望&mdash;&mdash;道生一,一生二 2008-01-14 15:52 duguguiyu
在贊一次。。。
我正在做一個(gè)二次開(kāi)發(fā)平臺(tái)。為了增加擴(kuò)展性和簡(jiǎn)單性,決定不用大而全的接口,而采用動(dòng)態(tài)的模板機(jī)制。今看此文,受益匪淺。
等我有了成熟一些的想法,再找老大討教。。。

PS:建議莫老大把鏈接的樣式改改,我等看客著實(shí)痛苦。。。:)  回復(fù)  更多評(píng)論
  

# re: GP技術(shù)的展望&mdash;&mdash;道生一,一生二 2008-01-14 20:17 duguguiyu
Another question...
如果沒(méi)有concept支持有辦法嗎? && 老大用的是什么編譯器,什么concept的實(shí)現(xiàn)?。。。

謝謝。。。  回復(fù)  更多評(píng)論
  

# re: GP技術(shù)的展望&mdash;&mdash;道生一,一生二 2008-01-15 08:23 longshanks
to duguguiyu:
如果沒(méi)有concept當(dāng)然可以,但是必須有一種完成concept功能,也就是類(lèi)型特征描述的機(jī)制,實(shí)現(xiàn)模板(泛型)的類(lèi)型參數(shù)約束,以及提供優(yōu)化線(xiàn)索的功能。
關(guān)于編譯器,靜態(tài)concept是未來(lái)C++09標(biāo)準(zhǔn)的一部分預(yù)計(jì)明年可以出臺(tái)。據(jù)我所知,現(xiàn)在只有一個(gè)試驗(yàn)性編譯器支持concept:conceptGCC,http://www.generic-programming.org/software/ConceptGCC/
而runtime concept,八字還沒(méi)一撇。Bjarne有一篇論文,可能在今年三月份發(fā)表,提到了runtime concept。但沒(méi)有涉及語(yǔ)言層面的實(shí)現(xiàn),而是庫(kù)方面的實(shí)現(xiàn)。相關(guān)這些內(nèi)容的其他文獻(xiàn),可以看我前一篇文章《OOP的黃昏》后面給出的參考。  回復(fù)  更多評(píng)論
  

# re: GP技術(shù)的展望&mdash;&mdash;道生一,一生二 2008-01-15 08:25 longshanks
btw:如何才能把鏈接的樣式改成標(biāo)準(zhǔn)樣式?我寫(xiě)的時(shí)候都是藍(lán)色帶下劃線(xiàn)的,但是發(fā)出來(lái)就不見(jiàn)了。  回復(fù)  更多評(píng)論
  

# re: GP技術(shù)的展望&mdash;&mdash;道生一,一生二 2009-01-21 15:46 kaperx
比較關(guān)心runtime concept的二進(jìn)制實(shí)現(xiàn),最后那張圖讓我茅塞頓開(kāi)。
但是有一個(gè)問(wèn)題,假如在二進(jìn)制模塊B中引入了新的Concept例如Printable,然后把來(lái)自模塊A的class Cycle map到Printable上,那么Printable<Cycle>的concept表如何處理?  回復(fù)  更多評(píng)論
  


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


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲一本大道在线| 国产视频丨精品|在线观看| 亚洲成人在线免费| 久久婷婷丁香| 久久久噜噜噜久久狠狠50岁| 激情婷婷久久| 91久久线看在观草草青青| 久久精品国产久精国产一老狼| 黄色日韩在线| 91久久极品少妇xxxxⅹ软件| 亚洲综合视频在线| 一区二区福利| 国产尤物精品| 91久久精品国产91久久性色tv | 久久久久看片| 免费视频最近日韩| 亚洲永久免费av| 久久国内精品视频| 夜夜夜久久久| 西西人体一区二区| 亚洲人成网站精品片在线观看| 99伊人成综合| 伊人久久大香线| 亚洲日韩成人| 一区二区亚洲精品国产| 亚洲精品影视| 在线欧美日韩国产| 亚洲香蕉成视频在线观看 | 国产精品久久久久免费a∨| 久久精品国产亚洲5555| 欧美精品久久99| 久久字幕精品一区| 国产精品久久久久久久久久尿| 欧美成人精品在线播放| 国产精品久久久久久久久久久久| 欧美大片在线观看一区| 国产欧美精品一区| 日韩视频不卡| 欧美成人午夜77777| 欧美一区二区国产| 欧美日韩裸体免费视频| 欧美大尺度在线| 国产一区二区精品久久91| 一区二区三区福利| 亚洲狼人精品一区二区三区| 久久国产欧美日韩精品| 欧美诱惑福利视频| 欧美日韩一区在线播放| 91久久久久久久久| 亚洲精品一区二区网址| 久久综合狠狠| 麻豆精品视频在线| 狠狠色狠色综合曰曰| 午夜一区二区三视频在线观看| 亚洲中字黄色| 欧美亚日韩国产aⅴ精品中极品| 亚洲国产一区二区三区a毛片| 亚洲第一在线视频| 久久亚洲私人国产精品va| 久久深夜福利| 激情久久五月天| 久久精品午夜| 麻豆九一精品爱看视频在线观看免费| 国产伦精品一区二区三区视频孕妇 | 蜜月aⅴ免费一区二区三区 | 欧美国产综合视频| 亚洲福利视频专区| 久久久免费精品| 久久黄金**| 国产又爽又黄的激情精品视频| 一本色道久久综合亚洲精品不卡| 中文在线一区| 国产九色精品成人porny| 亚洲影音一区| 久久成人18免费观看| 国产精品自拍视频| 欧美一区中文字幕| 蜜臀久久99精品久久久久久9| 亚洲黄色av一区| 欧美激情欧美狂野欧美精品| 99精品国产在热久久| 欧美一区三区二区在线观看| 国产日韩欧美日韩大片| 久久久久久久综合日本| 亚洲福利电影| 亚洲午夜在线观看| 韩国成人福利片在线播放| 免费成人性网站| 夜夜嗨av一区二区三区免费区| 亚洲欧美日本国产有色| 国产一区日韩二区欧美三区| 久久亚洲一区二区三区四区| 亚洲三级电影全部在线观看高清| 亚洲欧美国产一区二区三区| 狠狠久久亚洲欧美专区| 欧美极品一区二区三区| 亚洲欧美国产精品桃花| 欧美电影免费观看大全| 亚洲一区二区久久| 在线观看日韩www视频免费| 日韩一级在线| 久久久久五月天| 日韩午夜免费| 激情成人亚洲| 欧美视频中文字幕| 久久综合中文| 亚洲网在线观看| 亚洲黄色成人| 久久一区二区三区国产精品| 夜夜嗨av一区二区三区四区| 国产一区二区三区奇米久涩| 欧美日韩精品福利| 久久久久久香蕉网| 亚洲欧美激情四射在线日 | 在线日韩av永久免费观看| 国产精品黄色| 欧美男人的天堂| 蜜臀久久久99精品久久久久久| 欧美一区1区三区3区公司| 日韩小视频在线观看| 亚洲高清免费在线| 理论片一区二区在线| 久久黄色小说| 欧美一区二区三区男人的天堂| 一区二区欧美精品| 91久久精品美女| 亚洲狠狠丁香婷婷综合久久久| 韩日精品视频一区| 国产在线日韩| 国产视频丨精品|在线观看| 国产精品日韩在线观看| 欧美午夜不卡视频| 欧美日韩国产在线| 欧美另类99xxxxx| 欧美精品一区二区三区蜜桃| 美女精品网站| 美女图片一区二区| 免费成人黄色片| 在线视频一区观看| 国产综合色产在线精品| 国产女主播视频一区二区| 国产精品久久网| 国产精品国产三级国产aⅴ无密码| 欧美电影美腿模特1979在线看| 美女福利精品视频| 欧美国产综合视频| 欧美日韩国产丝袜另类| 欧美日韩国产综合网 | 美日韩免费视频| 免费的成人av| 欧美日本韩国一区| 欧美日韩三级一区二区| 国产精品高清在线观看| 国产欧美日韩在线播放| 国内精品久久久久久久影视蜜臀| 国产中文一区二区三区| 曰韩精品一区二区| 亚洲精品日韩在线| 亚洲天堂av在线免费观看| 性感少妇一区| 麻豆精品在线观看| 亚洲精品视频在线| 亚洲欧美日韩国产综合在线 | 亚洲欧美日韩另类| 久久先锋资源| 欧美日韩一区二区精品| 国产精品一二| 亚洲国产毛片完整版| 亚洲天堂久久| 久久偷看各类wc女厕嘘嘘偷窃| 亚洲成色www8888| 亚洲视频1区2区| 久久亚洲国产成人| 欧美午夜精品久久久久久久| 国产有码在线一区二区视频| 日韩视频免费观看高清在线视频| 国产亚洲精品美女| 亚洲日韩第九十九页| 欧美伊人久久久久久久久影院| 欧美91精品| 亚洲欧美日韩精品久久| 欧美黄色网络| 国产曰批免费观看久久久| 一区二区电影免费观看| 久久久亚洲人| 在线一区二区三区四区五区| 久久午夜激情| 国产一区二区精品在线观看| 在线视频一区二区| 免费在线欧美黄色| 亚洲欧美大片| 欧美日韩综合精品| 亚洲国产综合91精品麻豆| 欧美一区二区视频在线观看| 亚洲人体一区| 久久躁日日躁aaaaxxxx| 国产亚洲成av人片在线观看桃| 日韩小视频在线观看专区| 久热精品在线视频| 欧美亚洲综合网|