Modern C++ Design
2011-12-28 12:16
381 查看
第一章:Policy-Based Class Design
Policy Class (Template)
下面的这些Creater叫做“policy class (template)”。它们类似于设计模式里的strategy。它们是语法导向(syntax oriented),而不是标记导向(signature oriented)。换句话说,这些Creater定义的是”怎样的语法构造符合其所规范的class”,而不是“必须实例化那些函数”。
Host Classs Template
使用policy class (template)的叫做“host class (tempalte)”。host class (template)使用组合或者继承的方式使用policy class (template)。host负责把policy提供的结构和行为组合成更复杂的结构和行为。
使用host和policy:
template template 参数
从上面的使用方法上看,policy(OpNewCreator)还要接收一个模板类参数(Widget),然而作为一个WidgetManager它只能操作Widget,也就是说万一又一次有个程序员传了另外一个类给policy,那么就会因为和WidgetManager不兼容而出现问题。为了避免这种风险,可以使用“template template 参数”。
关于template tempalte parameter, 可以这么理解:WidgetManager这个类,是一个带有模板参数的类,它的模板参数是template <class Created> class CreationPolicy>,这个模板参数本身又是一个模板。使用作为模板参数的这个模板给WidgetManager指定基类:CreationPolicy<Widget>。可以印证WidgetManager的模板参数声明和使用的都是一个模板。这个作为WidgetManager的模板参数的模板的参数声明为class Created,使用为CreationPolicy中的Widget。
使用这个用模板做模板参数的模板的代码如下:
用模板作为模板参数还有一个好处,那就是:因为现在WidgetManager的模板参数是一个模板,你可以用这个模板来实例化别的模板类。比如在WidgetManager中已经使用了CreationPolicy<Widegt>(作为基类),你也可以把CreationPolicy派其它用途,比如我可以在WidgetManager里面使用CreationPolicy<Gadget>生成一个Gadget。
实际使用中,还可以给模板参数默认值,比如:
析构函数:
在上面的例子中,由于host类继承了policy类,所以用户可能会把host类指针向上cast到policy指针,并且删除它,这个时候为了保证子类(host)的析构函数会被调用,基类(policy)的析构函数必须是虚函数。然而引进虚函数会造成一定开销,所以我们想避免虚函数!怎么避免呢?方法如下:
给基类(policy)定义一个非虚的,但是处于protected级别的析构函数,在子类(host)的析构函数适当的调用基类(policy)的析构函数。这样,由于基类的析构函数是protected,那么只有host才能去调用之,也就是说如果你删除一个policy的指针,那是非法的。这样通过强行要求用户操作子类(host),避免了基类(policy)析构函数非虚的问题。
通过不完全具现化而获得的选择性机能
这话听着有点绕,但是它所实现的功能很美妙:)
问题是这样的:host 模板 WidgetManager所采用的policy可能是很简单的OpNewCreator,也可能是比较复杂的PrototypeCreator。注意所采用的policy决定了WidgetManager的基类。OpNewOperator只有一个Create函数给WidgetManager使用,而PrototypeCreator还有一个SetPrototype函数,而这个函数也必须要暴露给应用者。
问题就在于在这个暴露的方式:WidgetManager的所有逻辑都应该适用于所有的policy,那么似乎把PrototypeCreator所独有的函数暴露给WidgetManager不合适。
然而模板有一个特性:如果class template有一个成员函数没有被用到,那么编译器就不会去理会它,甚至不会为它进行语义检查。因此,我们可以这样暴露SetPrototype函数于WidgetManager中:
看上面的SwitchPrototype函数,如果你使用了PrototypeCreator作为policy,那么你可以使用SwitchPrototype;如果你使用了其它policy,你使用SwitchPrototype,会编译出错;如果是使用了其它prototype,但是没有使用SwitchPrototype,那么编译也会通过!这里面的关键点就在于我们得益于template的“不完全具现化而获得的选择性机能”(如本节的标题)
TODO
Policy Class (Template)
下面的这些Creater叫做“policy class (template)”。它们类似于设计模式里的strategy。它们是语法导向(syntax oriented),而不是标记导向(signature oriented)。换句话说,这些Creater定义的是”怎样的语法构造符合其所规范的class”,而不是“必须实例化那些函数”。
template <class T> struct OpNewCreator { static T* Create() { return new T; } }; template <class T> struct MallocCreator { static T* Create() { void* buf = std::malloc(sizeof(T)); if (!buf) return 0; return new(buf) T; } }; template <class T> struct PrototypeCreator { PrototypeCreator(T* pObj = 0): pPrototype_(pObj){} T* Create() { return pPrototype_ ? pPrototype_->Clone() : 0; } T* GetPrototype() { return pPrototype_; } void SetPrototype(T* pObj) { pPrototype_ = pObj; } private: T* pPrototype_; };
Host Classs Template
使用policy class (template)的叫做“host class (tempalte)”。host class (template)使用组合或者继承的方式使用policy class (template)。host负责把policy提供的结构和行为组合成更复杂的结构和行为。
template <class CreationPolicy> class WidgetManager : public CreationPolicy {}
使用host和policy:
typedef WidgetManager<OpNewCreator<Widget> > MyWidgetMgr;
template template 参数
从上面的使用方法上看,policy(OpNewCreator)还要接收一个模板类参数(Widget),然而作为一个WidgetManager它只能操作Widget,也就是说万一又一次有个程序员传了另外一个类给policy,那么就会因为和WidgetManager不兼容而出现问题。为了避免这种风险,可以使用“template template 参数”。
template <template <class Created> class CreationPolicy> class WidgetManager : public CreationPolicy<Widget> {...}
关于template tempalte parameter, 可以这么理解:WidgetManager这个类,是一个带有模板参数的类,它的模板参数是template <class Created> class CreationPolicy>,这个模板参数本身又是一个模板。使用作为模板参数的这个模板给WidgetManager指定基类:CreationPolicy<Widget>。可以印证WidgetManager的模板参数声明和使用的都是一个模板。这个作为WidgetManager的模板参数的模板的参数声明为class Created,使用为CreationPolicy中的Widget。
使用这个用模板做模板参数的模板的代码如下:
typedef WidgetManager<OpNewCreator> MyWidgetMgr;
用模板作为模板参数还有一个好处,那就是:因为现在WidgetManager的模板参数是一个模板,你可以用这个模板来实例化别的模板类。比如在WidgetManager中已经使用了CreationPolicy<Widegt>(作为基类),你也可以把CreationPolicy派其它用途,比如我可以在WidgetManager里面使用CreationPolicy<Gadget>生成一个Gadget。
实际使用中,还可以给模板参数默认值,比如:
template <template <class Created> class CreationPolicy = OpNewCreator> class WidgetManager : public CreationPolicy<Widget>{...}
析构函数:
在上面的例子中,由于host类继承了policy类,所以用户可能会把host类指针向上cast到policy指针,并且删除它,这个时候为了保证子类(host)的析构函数会被调用,基类(policy)的析构函数必须是虚函数。然而引进虚函数会造成一定开销,所以我们想避免虚函数!怎么避免呢?方法如下:
给基类(policy)定义一个非虚的,但是处于protected级别的析构函数,在子类(host)的析构函数适当的调用基类(policy)的析构函数。这样,由于基类的析构函数是protected,那么只有host才能去调用之,也就是说如果你删除一个policy的指针,那是非法的。这样通过强行要求用户操作子类(host),避免了基类(policy)析构函数非虚的问题。
通过不完全具现化而获得的选择性机能
这话听着有点绕,但是它所实现的功能很美妙:)
问题是这样的:host 模板 WidgetManager所采用的policy可能是很简单的OpNewCreator,也可能是比较复杂的PrototypeCreator。注意所采用的policy决定了WidgetManager的基类。OpNewOperator只有一个Create函数给WidgetManager使用,而PrototypeCreator还有一个SetPrototype函数,而这个函数也必须要暴露给应用者。
问题就在于在这个暴露的方式:WidgetManager的所有逻辑都应该适用于所有的policy,那么似乎把PrototypeCreator所独有的函数暴露给WidgetManager不合适。
然而模板有一个特性:如果class template有一个成员函数没有被用到,那么编译器就不会去理会它,甚至不会为它进行语义检查。因此,我们可以这样暴露SetPrototype函数于WidgetManager中:
template <template <class Created> class CreationPolicy> class WidgetManager : public CreationManager<Widget> { ... void SwitchPrototype(Widget* pNewPrototype) { CreationPolicy<Widget>& myPolicy = *this; delete myPolicy.GetPrototype(); myPolicy.SetPrototype(pNewPrototype); } }
看上面的SwitchPrototype函数,如果你使用了PrototypeCreator作为policy,那么你可以使用SwitchPrototype;如果你使用了其它policy,你使用SwitchPrototype,会编译出错;如果是使用了其它prototype,但是没有使用SwitchPrototype,那么编译也会通过!这里面的关键点就在于我们得益于template的“不完全具现化而获得的选择性机能”(如本节的标题)
TODO
相关文章推荐
- Modern C++ Design, Spring Framework和Ruby的Mixin....
- 关于Policy Based Class Design--《Modern C++ Design》读后感一
- Modern C++ Design 笔记 第七章 Smart Pointers
- Modern C++ Design 笔记 第十一章 MultiMethods(1)
- Modern c++ design 第8章
- Modern C++ Design 笔记 第九章 Abstract Factory
- Modern C++ Design 笔记 第十一章 MultiMethods(2)
- Modern C++ design 第三章 (上)
- Modern c++ design 第七章
- modern c++ design
- modern c++ design
- Modern C++ Design 学习笔记之Policy Based Class Design
- modern c++ design 第十一章
- 如何在编译时刻判断两个类型是否可以自动转换?——《Modern C++ Design》读书笔记(1)
- Modern C++ Design 笔记 第一章 Policy-Based Class Design
- 《Modern C++ Design》源码Loki库读解随感二:类型间耦合检测和去耦合
- Modern C++ Design 笔记 第二章 Chapter 2. Techniques
- 《Modern C++ Design》Loki库读解三:多继承的改良
- Modern C++ design 第三章 (下)
- Modern C++ design 第五章