二級考試C++基礎(類型和值之間的映射)

字號:

在C++中,術語“轉(zhuǎn)化”(conversion)描述的是從另外一個類型的值(value)獲取一個類型(type)的值的過程??墒怯袝r候你會需要一種不同類型的轉(zhuǎn)化:可能是在你有一個類型時需要獲取一個值,或是其它的類似情形。在C++中做這樣的轉(zhuǎn)化是不尋常的,因為類型域和值域之間隔有有一堵很嚴格的界線。可是,在一些特定的場合,你需要跨越這兩個邊界,本欄就是要討論該怎么做到這個跨越。
    映射整數(shù)為類型
    一個對許多的generic programming編程風格非常有幫助的暴簡單的模板:
    template
    struct Int2Type
    {
    enum { value = v };
    };
    對傳遞的每一個不同的常整型值,Int2Type“產(chǎn)生”一個不同的類型。這是因為不同的模板的實體(instantiation)是不同的類型,所以Int2Type<0>不同于Int2Type<1>等其它的類型的。此外,產(chǎn)生類型的值被“存放”在枚舉(enum)的成員值里面。
    不管在任何時候,只要你需要快速“類型化”(typify)一個整型常數(shù)時,你都可以使用Int2Type。
    問題描述:
    當需要根據(jù)不同的值選擇不同的行為時,普通的做法是利用if...else...或者case結(jié)構
    來實現(xiàn)分支選擇。在一個型別模板化的函數(shù)過程中,則可能出現(xiàn)問題。
    看下面的第一部分:
    Part 1
    如下的范型容器NiftyContainer的元素型別范型化為T。在容器中需要實現(xiàn)元素的賦值行為。非常規(guī)的自定義類型,其復制行為是復雜的。 特別是具有多態(tài)特性的類型和普通的類型,其復制過程不一樣。例如,普通類型可以采用逐位復制的簡單方式,而具有多態(tài)特性(例如含有指針成員)的類對象則不宜采用 這種方式。此處假定普通類型的復制采用拷貝構造函數(shù)方式而多態(tài)的類型則采用一個專門的虛函數(shù)clone來做拷貝。
    #include
    using namespace std;
    class Normal {
    int _i;
    public:
    Normal() { _i = 0; }
    Normal(const Normal& nml) { _i = nml._i; }
    // other members omitted
    };
    class Polym {
    int *_pi;
    Polym(const Polym&); // forbids copy-constructor
    void setp(int* i) { _pi = i; }
    public:
    Polym() { _pi = 0; }
    Polym* clone();
    // other members omitted
    };
    template
    class NiftyContainer
    {
    // other members omitted
    public:
    void DoSomething()
    {
    T* pSomeObj =new T;
    if (isPolymorphic) // branch1
    {
    T* pNewObj = pSomeObj->clone(); // customized behavior for copying
    // some operations on polymorphic object
    pNewObj = 0;
    }
    else // branch2
    {
    T* pNewObj = new T(*pSomeObj); // using copy-constructor
    // some operations on non-polymorphic object
    delete pNewObj;
    }
    delete pSomeObj;
    }
    // other members omitted
    };
    int main(int argc, char* argv[])
    {
    // using the container with elements' type Normal
    NiftyContainer nc;
    nc.DoSomething(); // error: 類Normal沒有成員函數(shù)clone
    // using the container with elements' type Polym
    NiftyContainer nc2; //error: 類Polym的copy-constructor private
    nc2.DoSomething();
    system("PAUSE");
    return EXIT_SUCCESS;
    }
    錯誤解析
    按照我們的預期,如果元素類型是多態(tài)的,那么只執(zhí)行branch1部分,否則只執(zhí)行branch2,因為兩種類型的元素有不同的拷貝函數(shù)。但是編譯器可不會理會這些,一律的都要加以編譯,因此出錯了。
    對于模板來說,不同的參數(shù)意味著不同的類型。 此外,模板的編譯有一個特性,即沒有用到的模板函數(shù)是不會參與到編譯中的,只進行語法正確性的分析。 函數(shù)可以根據(jù)參數(shù)進行重載。
    為了做到“根據(jù)常數(shù)的值(此處就是isPolymorphic)只編譯其中某一個分支(例如branch1),而不編譯其它分支,從而保證最后的代碼中只包含需要的代碼”, 我們可以利用上述的模板編譯特性和函數(shù)重載特性。
    template
    struct Int2Type { // 創(chuàng)造了這個模板是為了用不同的常數(shù)值產(chǎn)生不同的類型
    enum {value=v};
    };
    template
    class NiftyContainer
    {
    private:
    void DoSomething(T* pObj, Int2Type) // function_p
    {
    T* pNewObj = pObj->Clone();
    // some operations on polymorphic object
    pNewObj = 0;
    }
    void DoSomething(T* pObj, Int2Type) // function_n
    {
    T* pNewObj = new T(*pObj);
    // some operations on non-polymorphic object
    }
    public:
    void DoSomething(T* pObj)
    {
    DoSomething(pObj, Int2Type());
    }
    // other members are omitted
    };
    int main(int argc, char* argv[])
    {
    // using the container with elements' type Normal
    NiftyContainer nc;// ok
    // using the container with elements' type Polym
    NiftyContainer nc2; // ok
    system("PAUSE");
    return EXIT_SUCCESS;
    }
    在編譯過程中,根據(jù)傳遞的isPolymorphic模板參數(shù)值的不同,編譯器將選擇實現(xiàn)哪個函數(shù)。 若為true,則實現(xiàn)function_p,而不會嘗試去編譯function_n。 這樣就成功做到了編譯期多態(tài),而不是執(zhí)行期多態(tài)。
    這個技術的關鍵點就在于Int2Type模板。