第十六章标题就是 模版与继承,看到这个标题给我的第一反应就是蛋疼,模版和继承,对我来说这两个方面本身已经很复杂了,让它们进行结合....
不过人家不都是说么“有困难要学,没困难制造困难也要学!” 嗯,就是这个!通过周末两天的折腾,稍微看明白了一点思路,因此将这两天的所得写出来,希望大家一起学习,多多指教!
在许多模版技术中,往往需要模版带有几个长串的类型参数,并设有合理的缺省值,如下:
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 形成钻石型虚拟多重继承,避免了直接从多个相同类型的基类继承。