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