zoukankan      html  css  js  c++  java
  • C++ template 学习笔记(第十六章) 16.1 命名模版参数

    第十六章标题就是 模版与继承,看到这个标题给我的第一反应就是蛋疼,模版和继承,对我来说这两个方面本身已经很复杂了,让它们进行结合....

    不过人家不都是说么“有困难要学,没困难制造困难也要学!” 嗯,就是这个!通过周末两天的折腾,稍微看明白了一点思路,因此将这两天的所得写出来,希望大家一起学习,多多指教!

    在许多模版技术中,往往需要模版带有几个长串的类型参数,并设有合理的缺省值,如下:

    1 template <typename Policy1 = DefaultPolicy1,
    2          typename Policy2 = DefaultPolicy2,
    3          typename Policy3 = DefaultPolicy3,
    4          typename Policy4 = DefaultPolicy4 >
    5 class BreadSlicer
    6 {
    7 };

    因此使用的时候只需 BreadSlicer<> 即可,不过如果需要指定某个特点的参数为非缺省值的时候,必须将前面的参数一一写出来(即便前面的几个参数仍为缺省值)。

    如果将BreadSlicer< DefaultPolicy1, DefaultPolicy2, Custom > 可以实现为 BreadSlicer< Policy3 = Custom > 的方式,则会更加方便。
    为了解决这个问题,我们主要考虑将缺省值放入一个基类中,通过继承、覆盖的方式来实现对特定参数的修改。

    首先将缺省值集中到一个基类中:

    1 class DefaultPolices
    2 {
    3 public:
    4     typedef DefaultPolicy1 P1;
    5     typedef DefaultPolicy2 P2;
    6     typedef DefaultPolicy3 P3;
    7     typedef DefaultPolicy4 P4;
    8 };

    为了防止多次继承这个基类,而产生二义性问题,因此我们采用虚拟继承:

    class DefaultPolicyArgs : virtual public DefaultPolicies {};

    为了对缺省值进行修改,我们通过辅助类,覆盖掉基类缺省值即可:

     1 template <typename Policy>
     2 class Polic1_is : virtual public DefaultPolicies {
     3     public:
     4         typedef Policy P1;            //改写缺省的 typedef
     5 };
     6 
     7 template <typename Policy>
     8 class Polic2_is : virtual public DefaultPolicies {
     9     public:
    10         typedef Policy P2;            //改写缺省的 typedef
    11 };
    12 
    13 template <typename Policy>
    14 class Polic3_is : virtual public DefaultPolicies {
    15     public:
    16         typedef Policy P3;            //改写缺省的 typedef
    17 };
    18 
    19 template <typename Policy>
    20 class Polic4_is : virtual public DefaultPolicies {
    21     public:
    22         typedef Policy P4;            //改写缺省的 typedef
    23 };

    至此完成了对基类的处理,下面完成关于继承部分:

     1 //Discriminator<>产生4个不同的类,使PolicySelector 可以多次继承自相同的基类
     2 template < typename Base, int D >
     3 class Discriminator : public Base {
     4 };
     5 
     6 template <typename Setter1, typename Setter2, 
     7          typename Setter3, typename Setter4>
     8 class PolicySelector : public Discriminator<Setter1, 1>,
     9                     public Discriminator<Setter2, 2>,
    10                     public Discriminator<Setter3, 3>,
    11                     public Discriminator<Setter4, 4> {
    12 };

    上面部分完成了 PolicySelector 的设计部分,下面是使用部分:

     1 template <typename PolicySetter1 = DefaultPolicyArgs,
     2         typename PolicySetter2 = DefaultPolicyArgs,
     3         typename PolicySetter3 = DefaultPolicyArgs,
     4         typename PolicySetter4 = DefaultPolicyArgs>
     5 class BreadSlicer {
     6     typedef PolicySelector <PolicySetter1, PolicySetter2,
     7                         PolicySetter3, PolicySetter4>
     8             Poicies;
     9     //使用 Poicies::P1, Poicies::P2, Poicies::P3, Poicies::P4 来引用各个policies即可
    10 }

    至此完成了本次的任务。可以直接通过 BreadSlicer<Policy3_is<CustomPolicy> > bc; 直接设置第三个缺省值为 CustomPolicy
    由于我们自始至终都没有对它们进行实例化,因此也不存在性能或者内存损耗的问题。

    关于上面的实例中有两个关键点:
    首先是 DefaultPolicies 类,通过虚拟继承解决了,由于DefaultPolicies被多次继承而产生二义性问题。
        在虚拟继承中如果多次继承同一个基类,则会只保存一份基类,因此,在以后调用中使用 Policy3_is<CustomPolicy>, Policy2_is<CustomPolicy>等,

        虽然在不同的类中修改,但是他们修改的都是同一份基类的成员,而最后的结果调用则同样是直接调用基类的成员,因此实现了对默认成员的修改。


    其次是 Discriminator<Setter1, 1> 通过不同的模版参数,从而产生了几个不同的继承于同一个基类的类,在同时派生出 PolicySelector 形成钻石型虚拟多重继承,避免了直接从多个相同类型的基类继承。

  • 相关阅读:
    抽象类使用细节
    super关键字
    JDK,JRE,JVM三者之间的爱恨情仇
    LinkedHashSet
    HashSet扩容成红黑树机制
    Set之HashSet
    finally关键字
    Hashcode方法
    equals方法和==的区别
    LinkedList
  • 原文地址:https://www.cnblogs.com/fanqs/p/Template_16_1.html
Copyright © 2011-2022 走看看