zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    vue 封装数据字典项翻译方法
    vue 判断是否为移动端
    elementUI 日期控件
    Laravel 数据库backup 导入/导出
    yarn 安装出现 git 443 网络错误解决思路
    nvm简介
    nrm简介
    npm简介
    python 时间序列学习笔记
    java常见面试题——java常见笔试题
  • 原文地址:https://www.cnblogs.com/orangeform/p/2637170.html
Copyright © 2011-2022 走看看