Step By Step(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>。下面将给出一些具体的实现,请务必留意代码中的关键性注释:

 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

    在上面的例子中一个非常重要的特点是,所有的模板实参都是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 1
45     //The count of MyClass is 2
46     //The count of MyClass is 1
posted @ 2012-09-10 09:27  OrangeAdmin  阅读(7426)  评论(0编辑  收藏  举报