Step By Step(C++模板和繼承)

來源:互聯網
上載者:User

一、命名模板參數:

    有些進階指令碼語言,如Perl、PL/SQL等,他們的函數參數在調用時都支援具名引數,既在調用時可以不按照順序傳遞參數,而是p可以按照參數的名字傳遞。先看下面的程式碼範例:
    template<typename Policy1 = DefaultPolicy1,
             typename Policy2 = DefaultPolicy2,
             typename Policy3 = DefaultPolicy3,
             typename Policy4 = DefaultPolicy4>
    class BreadSlicer {
        ... ...
    }
    上面的模板類含有4個模板參數,如果要想指定其中的某個參數不為預設參數,那麼也必須同時指定其之前的所有模板參數,如:
    BreadSlicer<DefaultPolicy1,DefaultPolicy2,Custom>,然而我們更希望使用這樣的調用形式:BreadSlicer<Policy3 = Custom>。下面將給出一些具體的實現,請務必留意代碼中的關鍵性注釋:

 1     #include <stdio.h> 2     #include <typeinfo> 3     #include <conio.h> 4      5     //先定義出不同的策略類。 6     class DefaultPolicy1 {}; 7     class DefaultPolicy2 {}; 8     class DefaultPolicy3 {}; 9     class DefaultPolicy4 {};10     11     //該類將會是所有Policy Class的基類。他提供了預設的四個Policy的類型重定義。12     //因此在預設情況下,這四個Policy將會是BreadSlicer的四個Policy。13     class DefaultPolicies {14     public:15         typedef DefaultPolicy1 P1;16         typedef DefaultPolicy2 P2;17         typedef DefaultPolicy3 P3;18         typedef DefaultPolicy4 P4;19     };20     21     //這裡之所以給出中間類DefaultPolicyArgs,同時又讓該類以虛擬繼承的方式繼承22     //DefaultPolicies,一是為了避免後面在多重繼承同一基類時而導致的二義性,同時23     //也是為了方便後面其他類的繼承。24     class DefaultPolicyArgs : virtual public DefaultPolicies {25     };26     27     //這裡之所以有第二個常量模板參數,是為了避免重複繼承相同的基類。28     template<typename Base, int D>29     class Discriminator : public Base {30     };31     32     //在這裡,如果沒有Discriminator的常量模板參數,將極有可能導致繼承同一個基類。33     template<typename Setter1, typename Setter2, 34              typename Setter3, typename Setter4>35     class PolicySelector : public Discriminator<Setter1,1>,public Discriminator<Setter2,2>, 36         public Discriminator<Setter3,3>, public Discriminator<Setter4,4> {37     };38     39     template<typename PolicySetter1 = DefaultPolicyArgs,40         typename PolicySetter2 = DefaultPolicyArgs,41         typename PolicySetter3 = DefaultPolicyArgs,42         typename PolicySetter4 = DefaultPolicyArgs>43     class BreadSlicer {44     public:45         //在該類後面的實現中,不要直接使用模板參數,而是要使用Policies::P1, P2, P3, P4等。46         typedef PolicySelector<PolicySetter1,PolicySetter2,PolicySetter3,PolicySetter4> Policies;47         void DoTest() {48             printf("Policies::P1 is %s\n",typeid(Policies::P1).name());49             printf("Policies::P2 is %s\n",typeid(Policies::P2).name());50             printf("Policies::P3 is %s\n",typeid(Policies::P3).name());51             printf("Policies::P4 is %s\n",typeid(Policies::P4).name());52         }53     };54     55     template<typename Policy>56     class Policy1_is : virtual public DefaultPolicies {57     public:58         typedef Policy P1;   //改寫DefaultPolicies中的基於P1的typedef。59     };60     61     template<typename Policy>62     class Policy2_is : virtual public DefaultPolicies {63     public:64         typedef Policy P2;   //改寫DefaultPolicies中的基於P2的typedef。65     };66     67     template<typename Policy>68     class Policy3_is : virtual public DefaultPolicies {69     public:70         typedef Policy P3;   //改寫DefaultPolicies中的基於P3的typedef。71     };72     73     template<typename Policy>74     class Policy4_is : virtual public DefaultPolicies {75     public:76         typedef Policy P4;   //改寫DefaultPolicies中的基於P4的typedef。77     };78     79     class CustomPolicy {};80     81     int main() {82         BreadSlicer<Policy3_is<CustomPolicy> > bc;83         bc.DoTest();84         getch();85         return 0;86     }87     //Policies::P1 is class DefaultPolicy188     //Policies::P2 is class DefaultPolicy289     //Policies::P3 is class CustomPolicy90     //Policies::P4 is class DefaultPolicy4

    在上面的例子中一個非常重要的特點是,所有的模板實參都是DefaultPolicies的衍生類別。在聲明BreadSlicer對象時,不同的衍生類別將覆蓋不同的DefaultPolicies中的typedef。
    
二、遞迴模板模式:

    這是一種通用的模板設計模式,即衍生類別將本身作為模板參數傳遞給基類,如:
    template<typename DerivedT>
    class Base {
        ... ...
    };
    class MyDerived : public Base<MyDerived> {
        ... ...
    };
    基於這種模式,有一個非常著名的用例,即[MeyersCounting],是《Effective C++》的作者Scott Meyers所設計的。通過繼承以下代碼中的基類,所有的衍生類別便可實作類別執行個體計數的功能。在下面的基類中,將包含一個表示對象計數的靜態成員,同時還會在基類構造的時候遞增該值,並在析構的時候遞減該值,見如下程式碼範例:

 1     #include <stdio.h> 2     #include <conio.h> 3      4     template<typename CountedType> 5     class ObjectCounter { 6     private: 7         static size_t count; 8      9     protected:10         ObjectCounter() {11             ++ObjectCounter<CountedType>::count;12         }13         ObjectCounter(ObjectCounter<CountedType> const&) {14             ++ObjectCounter<CountedType>::count;15         }16         ~ObjectCounter() {17             --ObjectCounter<CountedType>::count;18         }19     20     public:21         static size_t liveCount() {22             return ObjectCounter<CountedType>::count;23         }24     };25     26     template<typename CountedType>27     size_t ObjectCounter<CountedType>::count = 0;28     29     //C++編譯器會根據模板參數的不同執行個體化不同類型的類對象,因此模板參數不同,所使用的靜態成員也是不同的。30     class MyClass : public ObjectCounter<MyClass> {31     };32     33     int main() {34         MyClass mc1;35         printf("The count of MyClass is %d\n",MyClass::liveCount());36         {37             MyClass mc2;38             printf("The count of MyClass is %d\n",MyClass::liveCount());39         }40         printf("The count of MyClass is %d\n",MyClass::liveCount());41         getch();42         return 0;43     }44     //The count of MyClass is 145     //The count of MyClass is 246     //The count of MyClass is 1
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.