• 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
  • 相关阅读:
    light oj 1105 规律
    light oj 1071 dp(吃金币升级版)
    light oj 1084 线性dp
    light oj 1079 01背包
    light oj 1068 数位dp
    light oj 1219 树上贪心
    light oj 1057 状压dp TSP
    light oj 1037 状压dp
    矩阵快速幂3 k*n铺方格
    矩阵快速幂2 3*n铺方格
  • 原文地址:https://www.cnblogs.com/orangeform/p/2637170.html
Copyright © 2020-2023  润新知