在没真正接触c++ 模板编程之前,真的没有想到c++ 还可以这么用,最大的感触是:太灵活了,太强大了。最初接触模板威力还是在Delta3d中,感觉里面的模板使用实在是灵活与方便,特别是dtAI中使用了大量的模板,大大增强了库的可扩展性。
本文基于《c++ 设计新思维》 而写。
先看一段代码:
#include <iostream>
#include <vector>
#include <list>
using namespace std;
//--------------------------------------------------------------------------------
/Widget类型
class SliderWidget
{
public:
SliderWidget()
{
std::cout<<"Slider Widget created"<<std::endl;
}
};
class BoxWidget
{
public:
BoxWidget()
{
std::cout<<"Box Widget created"<<std::endl;
}
};
//--------------------------------------------------------------------------------
//创建widget方法
template <class T>
class OpNewCreateor
{
public:
static T* create()
{
return new T;
}
protected:
~OpNewCreateor(){}
};
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;
};
//--------------------------------------------------------------------------------
//存储widget容器类型
template<class T>
class ContainerVec
{
public:
void push(T* widget)
{
mVecContainer.push_back(widget);
}
//protected://Container 不能是保护类型,因为WidgetManager 不继承此类
~ContainerVec(){}
private:
std::vector<T*> mVecContainer;//Vector容器
};
template <class T>
class ContainerList
{
public:
void push(T* widget)
{
mListContainer.insert(widget);
}
~ContainerList(){}//Container 不能是保护类型,因为WidgetManager 不继承此类
private:
std::list<T*> mListContainer;//List容器
};
//--------------------------------------------------------------------------------
//--------widget管理类
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(tmp);
return tmp;
}
private:
Container<T> mContainer;
};
//--------------------------------------------------------------------------------
typedef WidgetManager<BoxWidget,OpNewCreateor,ContainerVec> BoxWidgetManager;
typedef WidgetManager<SliderWidget,OpNewCreateor,ContainerList> SliderWidgetManager;
//--------------------------------------------------------------------------------
int main()
{
BoxWidgetManager boxWidgetManager;
BoxWidget * boxWidget = boxWidgetManager.create();
cout << typeid(BoxWidgetManager).name() << endl;
system( "pause");
}
什么是基于Policy编程
1. Policies机制是由templates和多继承组成 。
2. 而所谓policy,乃用来定义一个class或class template的接口,该接口由 “内隐型别定义 inner type definition),成员函数、或成员变量之一或全部组成。
3. policy接口和一般传统的class接口(virtual函数)不同,它比较 松散,这是因为policies 是语法导向(syntax oriented)而非标记导向(signature oriented)。也就是说上面的 createpolicy 明确定义的是:怎样的语法构造符合其所规范的class”,而非“必须实作出哪些函数”。createpolicy 并没有规范create()是virtual 还是static,它只要求必须定义出create函数。
4. 如果一个模板使用了policies,我们称其为host class ,如上面的widgetmanager。
Policy class 的析构函数
1. 大部分情况下,host class 会以 public 继承 方式从某些policies 派生而来,因此 使用者可以将一个host class 转换为一个 policy class ,并于稍后delete 该指针。
除非policy class 定义了一个 虚析构函数(virtual destructor) ,否则 delete一个指向policy class 指针,会有问题(最起码 这样会使得 host class 的析构函数没调用)
2. 如果把policy class 的析构函数 定义成虚析构函数,会妨碍policy的静态连接特性,也会影响执行效率。(引入一份vptr,也会带来额外开销),所以尽量避免虚析构函数
3. 许多policy class 并无数据成员,纯粹只是一个规范行为,policy class应该采用一个轻便而有效率的解法------定义一个non-vritual protected 析构函数。这样保证了只有继承者才能摧毁这个policy对象。
通过不完全具化而获得选择性机能
1. 意思是: 如果class template 有一个成员函数并未曾被用到,它就不会被编译器所具体实现出来。
以policy class 定制结构
通过policy class 不但可以定制行为,如要能够create,而且还可以定制结构。这个重要的性质使得policy-based design 超越了简单的型别泛化(type genericity),后者对于容器(container class )效力卓越。 (如上面的container policy)
下一步: c++ template traits