C++模板有很多特性需要我们去挖掘,很多新的设计模式也都与模板使用相关,我们知道模板的一个基本特性就是可以根据传入的类型产生新的类型。围绕这个特性,可以衍生出很多的其它特性,比如自动为不同的类生成static变量,为不同的类型生成不同的行为等等。
这篇文章我想讨论的是如何在C++模板中引用传入类的一个特定的成员变量。这个特性在我们设计新型类库的时候,很是有用。我今后想讲解的无内存管理的数据容器就与这个特性相关。
比如,如果我们想设计一个通用的Hash容器,我们肯定需要提供一个选择,让用户提供它们自己的Hash函数,同时,我们也需要提供一个默认的Hash函数,因为很多时候,我们只需要使用最简单的Hash函数,比如对于整数,我们取模(“%”)。这样如下的设计浮出水面:
template<classKeyType, class ObjType, ulong32 BucketNum, class HashFcn>
classHashContainer{
};
按照前面所述,我们需要提供一个默认的Hash函数,而这个函数,我们想让它以模板参数的形式传入,所以我们肯定需要实现一个仿函数:
ClassIntergerHasher{
Public:
Ulong32 operator()(KeyType key){
Return ulong32(key%BucketNum);
}
};
好的,问题好像来了。假如现在我们有两个类,它们想使用这个容器。这两个类的定义如下:
Class A{
Private:
Ulong32 fsid; //hash键值
};
Class B{
Private:
Ulong32 volid; //hash键值
};
它们都只需要默认的hash函数就行,那么我们的Hash模板如何知道它们使用哪个域来作为hash的键值呢?
这时,我想到了函数成员指针。也许我们可以利用它。所以定义了如下的模板构造函数:
template<classKeyType, class ObjType, ulong32 BucketNum, class HashFcn>
classHashContainer{
public:
HashContainer(KeyType ObjType::*key):mKey(key), mHasher(IntergerHasher<KeyType, BucketNum>())
{}
Void add(ObjType *p);
Private:
ObjType* ObjType::*mKey;
HashFcn mHasher;
};
这里视乎还有个问题,如何使用这个成员指针呢?我们以memberfunction add()为例:
template<classKeyType, class ObjType, ulong32 BucketNum, class HashFcn>
voidHashContainer<KeyType, ObjType, BucketNum, HashFcn >::add(ObjType *p)
{
ulong32 bucket = mHasher(p->*mKey);
…..
}
我们的模板有了这个技能,就可以如此的使用这个Hash容器了:
.hxx
Class A{
Private:
Ulong32 fsid; //hash键值
Static HashContainer<ulong32,A, 1543, IntegerHasher<ulong32, 1543>) manager;
};
Class B{
Private:
Ulong32 volid; //hash键值
Static HasherContainer<ulong32,B, 1543, IntegerHasher<ulong32, 1543>) manager;
};
.cxx
HashContainer<ulong32,A, 1543, IntegerHasher<ulong32, 1543> A::manager(&A::fsid);
HashContainer<ulong32,A, 1543, IntegerHasher<ulong32, 1543> A::manager(&B::volid);
也许你们会问,我们在HashContainer中可以使用A或B的私有变量吗?可以吗?你试试!!!