c++ 基於Policy 的 模板編程

在沒真正接觸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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章