Step By Step(C++模板和继承)
2012-09-10 09:27
489 查看
[b]一、命名模板参数:[/b]
有些高级脚本语言,如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>。下面将给出一些具体的实现,请务必留意代码中的关键性注释:
在上面的例子中一个非常重要的特点是,所有的模板实参都是DefaultPolicies的派生类。在声明BreadSlicer对象时,不同的派生类将覆盖不同的DefaultPolicies中的typedef。
[b]二、递归模板模式:[/b]
这是一种通用的模板设计模式,即派生类将本身作为模板参数传递给基类,如:
template<typename DerivedT>
class Base {
... ...
};
class MyDerived : public Base<MyDerived> {
... ...
};
基于这种模式,有一个非常著名的用例,即[MeyersCounting],是《Effective C++》的作者Scott Meyers所设计的。通过继承以下代码中的基类,所有的派生类便可实现类实例计数的功能。在下面的基类中,将包含一个表示对象计数的静态成员,同时还会在基类构造的时候递增该值,并在析构的时候递减该值,见如下代码示例:
有些高级脚本语言,如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>。下面将给出一些具体的实现,请务必留意代码中的关键性注释:
#include <stdio.h> #include <typeinfo> #include <conio.h> //先定义出不同的策略类。 class DefaultPolicy1 {}; class DefaultPolicy2 {}; class DefaultPolicy3 {}; class DefaultPolicy4 {}; //该类将会是所有Policy Class的基类。他提供了缺省的四个Policy的类型重定义。 //因此在缺省情况下,这四个Policy将会是BreadSlicer的四个Policy。 class DefaultPolicies { public: typedef DefaultPolicy1 P1; typedef DefaultPolicy2 P2; typedef DefaultPolicy3 P3; typedef DefaultPolicy4 P4; }; //这里之所以给出中间类DefaultPolicyArgs,同时又让该类以虚拟继承的方式继承 //DefaultPolicies,一是为了避免后面在多重继承同一基类时而导致的二义性,同时 //也是为了方便后面其他类的继承。 class DefaultPolicyArgs : virtual public DefaultPolicies { }; //这里之所以有第二个常量模板参数,是为了避免重复继承相同的基类。 template<typename Base, int D> class Discriminator : public Base { }; //在这里,如果没有Discriminator的常量模板参数,将极有可能导致继承同一个基类。 template<typename Setter1, typename Setter2, typename Setter3, typename Setter4> class PolicySelector : public Discriminator<Setter1,1>,public Discriminator<Setter2,2>, public Discriminator<Setter3,3>, public Discriminator<Setter4,4> { }; template<typename PolicySetter1 = DefaultPolicyArgs, typename PolicySetter2 = DefaultPolicyArgs, typename PolicySetter3 = DefaultPolicyArgs, typename PolicySetter4 = DefaultPolicyArgs> class BreadSlicer { public: //在该类后面的实现中,不要直接使用模板参数,而是要使用Policies::P1, P2, P3, P4等。 typedef PolicySelector<PolicySetter1,PolicySetter2,PolicySetter3,PolicySetter4> Policies; void DoTest() { printf("Policies::P1 is %s\n",typeid(Policies::P1).name()); printf("Policies::P2 is %s\n",typeid(Policies::P2).name()); printf("Policies::P3 is %s\n",typeid(Policies::P3).name()); printf("Policies::P4 is %s\n",typeid(Policies::P4).name()); } }; template<typename Policy> class Policy1_is : virtual public DefaultPolicies { public: typedef Policy P1; //改写DefaultPolicies中的基于P1的typedef。 }; template<typename Policy> class Policy2_is : virtual public DefaultPolicies { public: typedef Policy P2; //改写DefaultPolicies中的基于P2的typedef。 }; template<typename Policy> class Policy3_is : virtual public DefaultPolicies { public: typedef Policy P3; //改写DefaultPolicies中的基于P3的typedef。 }; template<typename Policy> class Policy4_is : virtual public DefaultPolicies { public: typedef Policy P4; //改写DefaultPolicies中的基于P4的typedef。 }; class CustomPolicy {}; int main() { BreadSlicer<Policy3_is<CustomPolicy> > bc; bc.DoTest(); getch(); return 0; } //Policies::P1 is class DefaultPolicy1 //Policies::P2 is class DefaultPolicy2 //Policies::P3 is class CustomPolicy //Policies::P4 is class DefaultPolicy4
在上面的例子中一个非常重要的特点是,所有的模板实参都是DefaultPolicies的派生类。在声明BreadSlicer对象时,不同的派生类将覆盖不同的DefaultPolicies中的typedef。
[b]二、递归模板模式:[/b]
这是一种通用的模板设计模式,即派生类将本身作为模板参数传递给基类,如:
template<typename DerivedT>
class Base {
... ...
};
class MyDerived : public Base<MyDerived> {
... ...
};
基于这种模式,有一个非常著名的用例,即[MeyersCounting],是《Effective C++》的作者Scott Meyers所设计的。通过继承以下代码中的基类,所有的派生类便可实现类实例计数的功能。在下面的基类中,将包含一个表示对象计数的静态成员,同时还会在基类构造的时候递增该值,并在析构的时候递减该值,见如下代码示例:
#include <stdio.h> #include <conio.h> template<typename CountedType> class ObjectCounter { private: static size_t count; protected: ObjectCounter() { ++ObjectCounter<CountedType>::count; } ObjectCounter(ObjectCounter<CountedType> const&) { ++ObjectCounter<CountedType>::count; } ~ObjectCounter() { --ObjectCounter<CountedType>::count; } public: static size_t liveCount() { return ObjectCounter<CountedType>::count; } }; template<typename CountedType> size_t ObjectCounter<CountedType>::count = 0; //C++编译器会根据模板参数的不同实例化不同类型的类对象,因此模板参数不同,所使用的静态成员也是不同的。 class MyClass : public ObjectCounter<MyClass> { }; int main() { MyClass mc1; printf("The count of MyClass is %d\n",MyClass::liveCount()); { MyClass mc2; printf("The count of MyClass is %d\n",MyClass::liveCount()); } printf("The count of MyClass is %d\n",MyClass::liveCount()); getch(); return 0; } //The count of MyClass is 1 //The count of MyClass is 2 //The count of MyClass is 1
相关文章推荐
- Step By Step(C++模板和继承)
- Step By Step(C++模板解析)
- Step By Step(C++模板目录)
- Step By Step(C++模板推演)
- Step By Step(C++模板推演)
- Step By Step(C++模板重载和特化)
- Step By Step(C++模板Trait)
- Step By Step(C++模板Trait)
- Step By Step(C++模板推演)
- Step By Step(C++模板Trait)
- Step By Step(C++模板基本技巧)
- Step By Step(C++模板目录)
- Step By Step(C++模板参数)
- Step By Step(C++模板重载和特化)
- Step By Step(C++模板解析)
- Step By Step(C++模板Policy)
- Step By Step(C++模板基本技巧)
- Step By Step(C++模板参数)
- 利用C++模板,代替虚函数实现类的静态多态性及动态继承
- Winform打砖块游戏制作step by step第5节---重构代码,利用继承多态