天天看點

C++模闆和繼承

一、命名模闆參數:

    有些進階腳本語言,如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>。下面将給出一些具體的實作,請務必留意代碼中的關鍵性注釋:

C++模闆和繼承
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 DefaultPolicy1
88     //Policies::P2 is class DefaultPolicy2
89     //Policies::P3 is class CustomPolicy
90     //Policies::P4 is class DefaultPolicy4      
C++模闆和繼承

    在上面的例子中一個非常重要的特點是,所有的模闆實參都是DefaultPolicies的派生類。在聲明BreadSlicer對象時,不同的派生類将覆寫不同的DefaultPolicies中的typedef。

二、遞歸模闆模式:

    這是一種通用的模闆設計模式,即派生類将本身作為模闆參數傳遞給基類,如:

    template<typename DerivedT>

    class Base {

        ... ...

    };

    class MyDerived : public Base<MyDerived> {

        ... ...

    };

    基于這種模式,有一個非常著名的用例,即[MeyersCounting],是《Effective C++》的作者Scott Meyers所設計的。通過繼承以下代碼中的基類,所有的派生類便可實作類執行個體計數的功能。在下面的基類中,将包含一個表示對象計數的靜态成員,同時還會在基類構造的時候遞增該值,并在析構的時候遞減該值,見如下代碼示例:

文章來自http://absoso.com/zhuanjiabaoliao/2012090934.html

C++模闆和繼承
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 1
45     //The count of MyClass is 2
46     //The count of MyClass is 1      
C++模闆和繼承