乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      C++的泛型編程和限制參數(shù)類型的技術探討

       9loong 2009-11-30
      http://blog.csdn.net/shendl/archive/2008/01/12/2040031.aspx
       
      模板概述
      泛型是C++中的重要特性。據(jù)說,已經(jīng)在C++社區(qū)中已經(jīng)取代面向對象成為C++的主要編程泛型。STL和boost庫等都廣泛使用了泛型。
      泛型,就是C++的模板機制。
      模板可以看作是C++宏的衍生。宏,就相當于是文本文件中的替換。C++編譯器在編譯前,先把所有使用宏的地方,用宏的定義替換掉宏。
      在Java,.net,ruby等現(xiàn)代語言中都沒有宏這種語法的地位。
      宏是另程序變得晦澀難懂的一個原因!我認為在程序中應該盡量避免使用宏!
       
      模板也可以看作是一種模板。C++編譯器在編譯之前,將創(chuàng)建模板的具體類型的源代碼,然后再編譯成二進制代碼。
       
       
       
      模板技術
       
      模板類的聲明和定義,形如:
      template<typename T> class Manage{全部內(nèi)聯(lián)函數(shù)實現(xiàn)!};
       
      函數(shù)模版的定義,形如:
       
       template<typename SequenceT> 
            void trim(SequenceT &, const std::locale & = std::locale());

      模板的特化
      模板類的特化

      1)首先定義基泛型:
      template<typename T> class Manage{全部內(nèi)聯(lián)函數(shù)實現(xiàn)!};

      2)然后定義特化的泛型:
      #include 上面基泛型的文件
      template<> class Manage<B>
      {全部內(nèi)聯(lián)函數(shù)實現(xiàn)!};
       
      特化的泛型必須自己實現(xiàn)所有基泛型定義的成員函數(shù)和靜態(tài)成員。
       
      模板類的成員函數(shù)的特化
      如果我們希望特化的泛型繼承絕大部分的基泛型的代碼。
      那么只需定義特化的成員函數(shù)即可!
      在基泛型的定義后面加上特化成員函數(shù):
      template<>
           void Manage<B>::sayHello(void){
           cout<<"B"<<this->t<<endl;
           };
      這個特化的函數(shù)就是特化模板類的成員函數(shù)。
      實際上,這相當于是隱式定義了上面的那樣一個特化模板類,并且所有的基本實現(xiàn)使用基泛型模板的實現(xiàn)!
       
      偏特化/部分特化
      就是一個模板類有多個泛型參數(shù)。
      我們特化一個模板參數(shù):
      1)基泛型有多個模板參數(shù):
      #pragma once
      #include "cppunit/extensions/HelperMacros.h"
      #include "B.h"
      #include <iostream>
      using namespace std;
       
      template<typename V,typename T> class Manage
      {
           private:
           T* t;
      public:
           Manage(void){
           this->t=new T();
           };
           void sayHello(void){
           cout<<"管理"<<this->t<<endl;
           };
       
      public:
           virtual ~Manage(void){};
      };
       

      2)定義的特化有一個還是任意的類型參數(shù)
      #pragma once
      #include "Manage.h"
       
      #include "B.h"
      #include <iostream>
      /*相當于
      template<typename V,沒有> class Manage<V,B>
      沒有對應已有的類型B
      */
      template<typename V> class Manage<V,B>
      {
      private:
           B* t;
      public:
           Manage(void){
           this->t=new B();
           }
           virtual ~Manage(void){}; 
      public:
           void sayHello(void){
               std::cout<<"B類"<<this->t<<std::endl;
           };
      };

          但是,請注意,半特化,則沒有特化中對應的成員函數(shù)的特化那種簡單扼要的形式?。?!
       
      模板的使用
      使用模板的類應該寫在頭文件中,并以源碼的方式發(fā)布
      C++的泛型編程中,需要把所有使用到泛型聲明或者定義的代碼都直接寫在.h頭文件中,不能寫在.cpp文件中,否則會有很多奇怪的錯誤!
       
      VC2005也還沒有支持分離編譯的export關鍵字!
       
      模板類只能寫在一個.h文件中。而且,不可以放在dll項目中。因為模板類是無法導出的!
      導出以后的模板類,只能夠在外部聲明這個模板類,不能夠實際創(chuàng)建模板類的對象!否則會報告
      TestMain.obj : error LNK2019: 無法解析的外部符號"__declspec(dllimport) public: __thiscall net_sf_interfacecpp_core_lang::ObjectRefManage<class AClass>::ObjectRefManage<class AClass>(void)" (__imp_??0?$ObjectRefManage@VAClass@@@net_sf_interfacecpp_core_lang@@QAE@XZ),該符號在函數(shù)_main 中被引用
      這樣的錯誤。
      因為,模板類實際上并沒能編譯成二進制代碼。它只是一個宏!需要在編譯時根據(jù)客戶代碼的使用情況生成源代碼,然后再變成二進制代碼。
      因此,作為宏,它應該在.h文件中。作為源代碼的元數(shù)據(jù),應該共享給用戶。因為它需要根據(jù)客戶的使用情況來生成源代碼。因此,它必須在最終客戶代碼一起!
       
      要使用模板類,就必須把它單獨拿出來,把.h這個頭文件/源代碼交給用戶。
      用戶在項目中直接作為源代碼使用這個頭文件,才能夠使用這個模板類!
      //確保只被引入系統(tǒng)一次
      #ifndef _net_sf_interfacecpp_core_lang_ObjectRefManage_h_
      #pragma once
      #include "..\net_sf_interfacecpp\IObject.h"
      //下面是自定義的所有.cpp文件都需要引入的頭文件
      //#include "ConfigApp.h"
      #include "..\net_sf_interfacecpp\Object.h"
       
      #pragma comment(lib,"..\\debug\\net_sf_interfacecpp.lib")
      /*
      用于管理任意類的實例的生命周期,使之符合IObject接口
      模板類必須定義在頭文件中
      NET_SF_INTERFACECPP_API
      */
       
      namespace net_sf_interfacecpp_core_lang{
      template<typename T>
      class   ObjectRefManage:public IObject
      {
      private:
           IObject* pIObject;
           T* pT;
               //copy構造函數(shù)
          ObjectRefManage(const ObjectRefManage &that);
           //重載等于操作符
        ObjectRefManage& operator=(const ObjectRefManage &that);
       //void operator delete(ObjectRefManage* thisPtr);
      public:
           T* getObjectPtrAndAddRef(){
              this->addRef();
              return this->pT;
           };
           T* getObjectPtrNotAddRef(){
              return this->pT;
           };
           ObjectRefManage(void){
               //現(xiàn)在引用是
           this->pIObject=new Object();
           this->pT=new T();
           };
       long addRef(){
              return this->pIObject->addRef();
           };
           long release(){
            long result=this->pIObject->release();
            if(result==0){
              delete this->pT;
              delete this;
              return 0;
            }
           };
      void setSingleton(){
              this->pIObject->setSingleton();
           };
      public:
           virtual ~ObjectRefManage(void){};
      };
      }
      //確保只被引入系統(tǒng)一次
      #define _net_sf_interfacecpp_core_lang_ObjectRefManage_h_
      #endif

      dll依賴模板時使用方式
      1)模板依賴于我們的dll
      2)如果我們的類需要使用這個模板,就需要另外建一個dll—ext.dll,包括這個模板,從而間接包括核心dll。
      Dll內(nèi)部時可以使用模板的,因為可以直接在生成dll時根據(jù)內(nèi)部的使用模板的情況,創(chuàng)建源代碼,編譯成dll。
      但是,如果把dll內(nèi)部的模板發(fā)布出去,這就不行了!
      3)這個模板頭文件和dll必須同時提供,避免找不到模板依賴的dll而出錯!
       
       
       
      對模板參數(shù)沒有限制是一大誤區(qū)
      考察STL和boost中使用泛型的例子。我發(fā)現(xiàn)一個問題。使用模板的類,在使用時,程序員可以指定任何類和基本類型。
      但是,實際上,很多模板類在代碼的內(nèi)部實現(xiàn)中,對參數(shù)類型能夠提供的操作實際上是有要求的。如,需要>,<,=等操作是有意義的。
      或者需要能夠調(diào)用某個方法。
      但是,STL和boost的庫中,均沒有對參數(shù)進行限制!
      這樣,如果客戶程序員使用了錯誤的參數(shù)類型,那么程序還是能夠正常編譯。只有在運行到這段代碼時,才會報錯。
      甚至,由于STL和boost喜歡使用操作符重載,因此,即使運行時,也不會出錯,只是真正的邏輯錯了。這樣的問題,怎么才能找到錯誤點呢?我不禁倒吸了一口涼氣!
       
      翻開C++之父BS的《C++語言的設計與演化》一書,BS本人對模板的這一描述,令我乍舌!
      BS居然認為不需要限制模板的參數(shù)類型。認為對模板參數(shù)的限制是OOP程序員的偏見!
      暈!C++是靜態(tài)編譯型語言,不是ruby,python,JavaScript這樣的動態(tài)面向對象語言。
      如果ruby開發(fā)中,你用了錯誤類型的對象,執(zhí)行時沒有報錯,直到你運行到這段代碼才報錯,那我也沒什么話好說的。人家是解釋型語言,放棄了編譯檢查錯誤,但換來了語言的巨大動態(tài)靈活性。有所得必有所失嘛!這我就不說它了!
      但BS認為C++不應該限制模板的參數(shù)類型,聽任錯誤在運行時爆發(fā),就讓我無法理解了!
       
      BS,不能因為你對模板的偏愛,讓這么多C++程序陷入危險?。?br> 
      通過派生對模板的參數(shù)類型加以限制的一種方法。
      形如:
      Template <typename T> class Compare{};
      Template <typename T: Compare > class Vector{};
      BS認為不應該采用這種方式。
      在java中使用模板時,我們經(jīng)常使用這種方式。
      如:
      Public MyClass<E extends String>{……}
       
      但,BS認為這種方式不好。而且我在VS2005中也無法編譯這樣的代碼。
      確實,這樣會讓模板類的數(shù)量直線上升。
       
      第二種BS提到的方法非常丑陋。
      就是讓每一個方法的實現(xiàn)都轉換成我們需要的類型。這樣編譯時就會報錯。
       
      第三種方法,就是使用模板的特化,或者叫做專門化。
      這是BS推薦使用的方法。我也認為應該使用模板特化來限制模板的參數(shù)類型。
      盡管BS提出這種語法的本意并不是用來限制模板的參數(shù)類型。
      因為,BS根本就不認為應該限制模板的參數(shù)類型。偏執(zhí)的家伙!

      使用模板特化限制模板的參數(shù)類型
      作為一個堅定的OO程序員,我是不會容許在自己的C++程序中像STL和boost那樣,允許任意參數(shù)類型隨意使用我的模板類的!
      BS的觀點,我不能茍同!
       
      我認為,可以使用模板特化限制模板的參數(shù)類型。這種辦法是最簡單有效的。
      首先,我們定義一個基范型。
       
      然后再在基范型模板類的外部定義幾個重載的方法。
      指定如果是我們需要的參數(shù)類型,應該執(zhí)行這些方法。
       
      也可以獨立定義特化的模板類。但是,我們上面已經(jīng)說過了,特化模板類,不如特化模板類的成員函數(shù)合算!
       
      最后,我們在基范型的實現(xiàn)中,拋出一個自定義的異常。這樣,如果使用了錯誤的類型,就會拋出異常,導致系統(tǒng)停止運行。我們的客戶就可以發(fā)現(xiàn)問題所在。
       
      當然,編譯時,即使是不正確的類型,還是能夠編譯通過。只有在運行時才會把錯誤抓出來。
      編譯時檢查不出錯誤,這只能怪BS和C++標準委員會沒有為我們提供限制模板的參數(shù)類型的語法了。
       
       
      補充:C++的模板和java的模板的異同
      Java5中,也引入的泛型語法。如:
      Public MyClass<E extends String>{
      ……
      }

      看上去類似,但是實際實現(xiàn)卻非常不同。
      C++的模板,是會在編譯時,先生成很多新的C++類。因此,C++中使用模板有一個問題,就是模板生成的源代碼可能太多。引起編譯的性能問題。
       
      而java的模板實現(xiàn)機制完全不同。Java模板類在編譯時,會“擦除”類型信息。
      不會生成新的java類的源代碼。
      因為,java的類繼承體系是單根的,所有類都是Object類的子類。因此,在Java5之前,沒有引入模板這個語法之前,java和它的集合實現(xiàn)類也過得很滋潤。
      Java模板類在編譯時,我猜想是這樣子的:
      1,首先,擦除模板類型的信息,還是使用原來的Object類型。
      2,在所有使用模板的參數(shù)類型的地方,加上強制類型轉換,轉換成程序員指定的模板參數(shù)類型。
       
      我特別記得BS的一句話,認為特有道理:
      他在C++中特別把不應該使用的語法設計得丑陋,讓你不想去使用。如:
      dynamic_cast < type-id > ( expression )
      動態(tài)類型轉換。
      BS認為,顯式的類型轉換通常是不必要的。應該避免。
       
      我深深地贊同這句話。Java引入模板,應該就是為了這個原因。現(xiàn)在,寫Java代碼可以少用很多強制類型轉換!
      用錯模板的參數(shù)類型,Java編譯器都會準確地報告錯誤。
       
      唉,C++的模板要是也這樣就好了!
       

      本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/shendl/archive/2008/01/12/2040031.aspx
       
      (#)

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多