一、首先分析THashObj类。
THashObj类的声明如下:
//tmisc.h/line16
class THashObj
{
public:
THashObj *priorHash;
THashObj *nextHash;
u_int hashId;
public:
THashObj() { priorHash = nextHash = NULL; hashId = 0; }
virtual ~THashObj() { if (priorHash && priorHash != this) UnlinkHash(); }
virtual BOOL LinkHash(THashObj *top);
virtual BOOL UnlinkHash();
friend THashTbl;
};
(1)成员变量
THashObj *priorHash;
THashObj *nextHash;
u_int hashId;
成员变量有三个,分别是自身类型的两个指针,和一个unsigned int类型的整型值。按照字面意思的理解,两个指针分别指向一个链表中自身前后的两个对象。
(2)构造函数
THashObj()
{
priorHash = nextHash = NULL;
hashId = 0;
}
构造函数,就是初始化这个类的成员变量,将指针赋值null,将整型值赋值为0。
(3)虚析构函数
virtual ~THashObj()
{
if (priorHash && priorHash != this)
UnlinkHash();
}
虚析构函数的作用:
析构函数执行的时候先调用派生类的析构函数,其次才调用基类的析构函数,如果析构函数不是虚函数,而程序执行的时候又要通过基类的指针去销毁派生类的动态对象,那么用delete销毁对象的时候,只调用了基类的析构函数,未调用派生类的析构函数,这样会造成销毁对象的不完全。
注意应该为多态基类声明虚析构器。一旦一个类包含虚函数,它就应该包含一个虚析构器。如果一个类不用作基类或者不需要具有多态性,那就不该为它声明虚析构器。
虚函数的作用就是实现多态性,即通过指向派生类的基类指针或者引用去访问派生类中同名的覆盖成员函数。就是实现以共同的方法,但是因为个体的差异,而采取不同的策略。
这里THashObj作为基类,所以析构函数最好定义成虚函数。本析构函数的功能是在priorHash指针不为空并且priorHash不指向自身的情况下,调用UnlinkHsah()函数。
(4)virtual BOOL LinkHash(THashObj *top);
//tmisc.cpp/line23
BOOL THashObj::LinkHash(THashObj *top)
{
if (priorHash)
return FALSE;
this->nextHash = top->nextHash;
this->priorHash = top;
top->nextHash->priorHash = this;
top->nextHash = this;
return TRUE;
}
本函数的功能就是将本对象作为一个节点链接到top节点的后面,这个数据结构是双向链表。如果priorHash指针有值的话,就不链接,返回链接错误。
(5)BOOL THashObj::UnlinkHash();
//tmisc.cpp/line34
BOOL THashObj::UnlinkHash()
{
if (!priorHash)
return FALSE;
priorHash->nextHash = nextHash;
nextHash->priorHash = priorHash;
priorHash = nextHash = NULL;
return TRUE;
}
如果priorHash的指向为空的话,就不做任何操作,取消链接操作返回FALSE。如果priorHash有指向的对象的话,就把本对象对应的那个节点从双向链表中给拿掉,取消链接的操作成功的话,就返回TRUE值。
(6)友元类
THashTbl类是THashObj类的友元类。THashTbl类中的成员函数可以访问类THashObj类的私有成员。但是THsahObj中是没有私有成员的,这个友元关系就是指的是THashTbl类可以访问THsahObj类的所有成员。
二、分析THashTbl类。
声明如下:
//tmisc.h/line31
class THashTbl
{
protected:
THashObj *hashTbl;
int hashNum;
int registerNum;
BOOL isDeleteObj;
virtual BOOL IsSameVal(THashObj *, const void *val) = 0;
public:
THashTbl(int _hashNum=0, BOOL _isDeleteObj=TRUE);
virtual ~THashTbl();
virtual BOOL Init(int _hashNum);
virtual void UnInit();
virtual void Register(THashObj *obj, u_int hash_id);
virtual void UnRegister(THashObj *obj);
virtual THashObj *Search(const void *data, u_int hash_id);
virtual int GetRegisterNum() { return registerNum; }
// virtual u_int MakeHashId(const void *data) = 0;
};
(1)成员变量
protected:
THashObj *hashTbl;
int hashNum;
int registerNum;
BOOL isDeleteObj;
THashTbl的成员变量有四个,是protected类型。
(2)virtual BOOL IsSameVal(THashObj *, const void *val) = 0;
IsSameVal是一个纯虚函数,需要派生类进行实现,否则不能使用。
(3)THashTbl(int _hashNum=0, BOOL _isDeleteObj=TRUE);
构造函数。构造函数可以接受一个和两个参数,接受一个参数的时候,_isDeleteObj参数的默认值是TRUE.
//tmisc.cpp/line45
THashTbl::THashTbl(int _hashNum, BOOL _isDeleteObj)
{
hashTbl = NULL;
registerNum = 0;
isDeleteObj = _isDeleteObj;
if ((hashNum = _hashNum) > 0)
{
Init(hashNum);
}
}
初始化hashTbl,registerNum参数为NULL,0;接着初始化isDeleteObj为_isDeleteObj,初始化hashNum的值为_hashNum。如果hashNum的值大于0的话,就调用本函数的Init函数。
(4)virtual ~THashTbl();
析构函数
THashTbl::~THashTbl()
{
UnInit();
}
析构函数就是简单的调用了成员函数UnInit();
(5)virtual BOOL Init(int _hashNum);
//tmisc.cpp/line61
BOOL THashTbl::Init(int _hashNum)
{
if ((hashTbl = new THashObj [hashNum = _hashNum]) == NULL)
{
return FALSE; // VC4's new don't occur exception
}
for (int i=0; i < hashNum; i++)
{
THashObj *obj = hashTbl + i;
obj->priorHash = obj->nextHash = obj;
}
registerNum = 0;
return TRUE;
}
参数是整型值_hashNum.整型值的含义是即将创建的饿THashObj类型数组的大小。
创建THashObj类型大小为_hashNum的数组hashTbl.同时初始化类成员变量hashNum。这里我认为应该加上一个过滤语句,使得hashNum的大小大于0;
总之如果创建hashTbl数组不成功的话,就返回FALSE的值。
然后进入循环,遍历hashTbl数组中每一项,让每一项的priorObj和nextHash都指向自己。这也是初始化的工作。
最后初始化registerNum成员变量为0;初始化完毕返回true的值。
(6)virtual void UnInit();
//tmisc.cpp/line75
void THashTbl::UnInit()
{
if (hashTbl)
{
if (isDeleteObj)
{
for (int i=0; i < hashNum && registerNum > 0; i++)
{
THashObj *start = hashTbl + i;
for (THashObj *obj=start->nextHash; obj != start; )
{
THashObj *next = obj->nextHash;
delete obj;
obj = next;
registerNum--;
}
}
}
delete [] hashTbl;
hashTbl = NULL;
registerNum = 0;
}
}
如果hashTbl为空的话,那么本函数就什么也不做。
如果isDeleteObj为假的话,就直接删除hashTbl数组,将hashTbl指针置空,将registerNum置零。
如果isDeleteObj为真的话:进入双循环。此双循环的目的是删除已hashtable数组中各个节点为头结点的各个链表。然后就直接删除hashTbl数组,将hashTbl指针置空,将registerNum置零。
(7)virtual void Register(THashObj *obj, u_int hash_id);
//tmisc.cpp/line95
void THashTbl::Register(THashObj *obj, u_int hash_id)
{
obj->hashId = hash_id;
if (obj->LinkHash(hashTbl + (hash_id % hashNum))) {
registerNum++;
}
}
将THashObj类obj对象的hashId的值设置为hash_id参数的值。
将obj对象对应的节点链接到,以hashTbl数组第hash_id % hashNum个元素为头节点的双向链表中,头节点的后面。如果链接成功的话,registerNum自加一。否则直接返回。
我认为这里应该给出来一个添加节点不成功时的报警消息。不成功的原因我还没想到,但是有这么一个消息存在的话,会提高系统整体的稳定性的吧。
(8)virtual void UnRegister(THashObj *obj);
//tmisc.cpp/line104
void THashTbl::UnRegister(THashObj *obj)
{
if (obj->UnlinkHash())
{
registerNum--;
}
}
调用对象obj的UnlinkHash()函数,从哈希链表结构中删除节点,同时更新当前注册的哈希节点的值,就是使得成员变量registerNum减一。
(9)virtual THashObj *Search(const void *data, u_int hash_id);
//tmisc.cpp/line111
THashObj *THashTbl::Search(const void *data, u_int hash_id)
{
THashObj *top = hashTbl + (hash_id % hashNum);
for (THashObj *obj=top->nextHash; obj != top; obj=obj->nextHash) {
if (obj->hashId == hash_id && IsSameVal(obj, data)) {
return obj;
}
}
return NULL;
}
首先根据hash_id找到头结点top。遍历以头节点为top的双向链表结构,查找hashId相同并且调用IsSameVal函数的返回值为true的THashObj节点,返回该节点的指针。如果找不到就返回NULL。
(10)virtual int GetRegisterNum() { return registerNum; }
本函数就是返回成员变量registerNum的值。registerNum的值表示的就是hash链表结构中节点的个数。