Modern C++ Design(一)
Template 是一种很适合组合各种行为的机制,主要是因为他们依赖使用者提供的型别信息并且在编译起才产生的代码
和一般的clas不同,class templates可以以不同的方式定制,如果想要针对特定的情况来设计class,你可以在你的class template中特化其成员函数来因应。
对于带有多个参数的class template,你可以采用partial template speciallization。他可以让你根据部分参数来特化一个class template。
template的编译期特性以及可互相组合特性,使得它在设计期非常引人注目,然而一旦你开会开始尝试做这些设计,你会遭遇一些不是那么浅白的问题:
1.你无法特化结构,单单使用templates,你无法特化class结构,你只能特化其成员函数
2.成员函数的特化并不能依里扩张,你可以对单一template参数的class templateTeha特化其成员函数,却无法对着多个template参数的class template特化其个别成员数。
3。程序库撰写者不能提供多个缺省值,理想情况下class template的作者可以对每个成员函数提供一个缺省实作品,却不能对同一个成员函数提供多个缺省实作品。
现在让我们比较一下多重继承和template之间的缺点,又去的是两者互补,多重继承欠缺的技术,template有丰富的技术,多重继承缺乏心别信息,而拿东西在template里大量存在。template的特化无法扩张,多重继承却很容易扩张,你只能为template成员函数写一份缺省版本,但你可以写数量无数的base class
根据以下分析,如果我们将template和多重继承组合起来,将会产生非常具有弹性的设计,应该社和用来产生程序库中的设计元素
Policies 和policies classes
所谓policies,乃是用来定义一个class或者class template的接口,该接口由下列项目之一或者全部组成:
内隐型别、成员函数和成员变量。
Policies也被其他人用于traits,不同的是后者比较重视行为而非型别。
这里有一个重要概念,Policies接口和一般传统的classses接口(纯虚函数集)不同,他比较松散。因为Policies是语法导向而非标记导向。换句话说,createor明确定义的是怎么样的语法构造符合其规范的class,而非必须室作出那些函数。例如,creator Policy 并没有规范create()必须是static还是virtual,他只要求class必须定义出create(),此外,creator也只规定create()应该传回一个指向新对象的指针。一维create()也许会传回0或者丢出异常。
面向一个policy,你可以作出数个policy classes。他们全部都必须遵守policy所定义的接口。
现在让我们看看如何设计一个class得以利用creator policy,它以复合或者继承的方式使用先前定义的三个classes之一,例如
template<class CreationPolicy>
class WidgetManager:public CreationPolicy
{......};
如果class采用一个或者多个Policies,我们称其为hosts或host classes。上例的widgetManager辨识采用了一个policy的hostclass。hosts负责把Policies提供的结构和行为组成一个更复杂的结构和行为。
当客户端将widgetmanager tmeplate 具象化时,必须传进一个他所期望的policy
typedef WidgetManager<OpNewCreator<Widget> > MyWidgetMgr;无论何时,当一个MyWidgetMgr对象要产生一个Widget对象时,他便调用它的policy对象OpNewCreator<Widget>所提供的create()。选择生成策略widget使用者的权利。皆借组这样的设计,可以让widgetManager使用者自行装配他所需要的机能。
这便是policy-based class设计的主旨。
运用template template 参数实作policy classes
如同先前的例子所示,policy的template引数往往是多余的,使用着每次需要传入template引数给OpNewCreator,这很笨拙,一般来说,host class 已经知道policy class 所需参数,或是轻易便可推导出来,上述例子中widgetManager总是操作widget对象,这种情况下还要求使用者把widget型别传给OpnewCreator,就显得多余且危险。
#include<iostream> #include<vector> #include<list> using namespace std; class SliderWidget { public: SliderWidget(); { std::cout<<"Slider Widget created"<<std::endl; } }; class BoxWidget { public: BoxWidget() { std::cout<<"Box Widget created"<<std::endl; } }; template <class T> class OpNewCreator{ public: static T* create() { return new T; } protected: ~OpNewCreator(){} }; template <class T> class MallocCreator { public: static T* create() { void *buf=std::malloc(sizeof(T)); if(!buf) return 0; return new(buf) T; } protected: ~MallocCreator(){} }; template <class T> class PrototypeCreator { public: PrototypeCreator(T * pObj=0):pPrototype(pObj) { } T* create() { return pPrototype?pPrototype->clone():0; } T* getPrototype(){return pPrototype;} void setPrototype(T* pObj){pPrototype=pObj;} protected: ~PrototypeCreator(){} private: T* pPrototype; } template<class T> class ContainerVec { public: void push(T* widget) { mVecContainer.push_back(widget); } ~ContainerVec(){} private: std::vector<T*> mVecContainer; }; template<class T> class COntainerList { public: void push(T* widget) { mListContainer.insert(widget); } ~containerList(){} private: std::list<T*> mListContainer; }; template<class T, template<class> class CreationPolicy=MallocCreator, template<class> class Container=ContainerVec > class WidgetManager:public CreationPolicy<T> { public: typedef CreationPolicy<T> BaseClass; T* create() { T* tmp=BaseClass::create(); mContainer.push_back(tmp); return tmp; } private: Container<T> mContainer; } typedef WidgetManager<BoxWidget,OpNewCreator,ContainerVec> BoxWidgetManager; typedef WidgetManager<SliderWidget,OpNewCreator,ContainerList> SliderWidgetManager; int main() { BoxWidgetManager boxWidgetManager; BoxWidget* boxWidet=boxWidgetManager.create(); cout<<typeid(BoxWidgetManager).name()<<endl; system("pause"); }