Veneers的概念相當簡單,一個Veneer其實就是一個類模板,它擁有以下特征:
1)它從自己的主模板參數派生而來(常以public方式)
2)它不定義任何虛方法
3)它不定義任何非靜態成員變量,也不定義虛擬析構方法
4)在2)和3)的基礎上更進一步,相比於模板參數類,它並不會增加復合類的內存訪問頻率。
Veneers常常更改了模板參數類的行為或類型。更改行為采用的方法是使用次模板參數提供的額外功能來補充現有功能。
考慮一種情況:向一個非常嚴密的層次結構中注入新的功能,ATL中的CWindow是一個很好的例子。CWindow沒有可以獲取對話欄文本長度的成員函數,我們可以使用Win32的API函數GetWindowTextLength()以及CWindow的成員函數GetDlgItem()來創建一個Veneer類parent_window_veneer,其代碼如下所示:
template<typename T>
classparent_window_veneer : public T
{
public:
typedef T ParentClass;
typedef parent_window_veneer<T> Class;
//construction
public:
……
//operations
public:
int GetDlgItemTextLength(UINT id)
{
return ::GetWindowTextLength(GetDlgItem(id));
}
};
任何可能用到CWindow類的地方都可以用parent_window_veneer<CWindow>替換,這樣一來GetDlgItemTextLength()方法在該類或該類的派生類的實例中就可以使用了。當然不采用模板化繼承也可以實現這一功能,但是如果之後你又想將這個函數添加到另外一個ATL窗口類(如CContainedWindow)中,你就不得不再寫一個派生類,以此類推。Veneer很容易被各種類型的窗口類使用,只要它們含有兼容的GetDlgItem()成員函數即可,剩下唯一要做的事就是修改一下類型定義(typedef)。
Veneers也可以提供析構方法,不過需要注意的是:如果模板參數不是一個多態可繼承的類型(比如它不包含一個虛擬析構方法),就不要將它多態地使用。
最後,因為Veneers與它們的模板參數類型大小相同,因此在需要數組的情況下可以用Veneers替換其模板參數類型。
Veneers的優勢包括:
在不重復編寫代碼的前提下向繼承層次結構成功注入了新的功能代碼
它們可被用來向已存在的類中增加資源自動清理的功能,常使用RAII手法。(STLSoft庫中的容器Veneers為C++標准庫中的容器類提供了這樣的功能)
大小的限制意味著參數化的Veneer類型可以在數組形式中使用,而不會碰到異構數組的問題
STLSoft庫中有一些Veneers類的實際例子,包括pod_veneer,conversion_veneer,sequence_container_veneer以及associative_container_veneer。你可以查看這些類的說明文檔以加深對Veneers概念的理解。
來源:http://synesis.com.au/resources/articles/cpp/veneers.pdf
翻譯:ume@2011-12-03
關鍵字:模板化繼承、泛型繼承、templatedinheritance、generic inheritance、Veneers