CMap用法的精辟解释

如何声明CMAP

许多人Cmap的声明模式CMap<KEY,ARG_KEY,VALUE,ARG_VALUE>感到迷惑,不用CMap<KEY,VALUE>呢?

实际上,CMap中的数据最会是CPair,而CPair内部是(KEYVALUE)。因此,CMap的是KEY,而非ARG_KEY。然而,如果你MFC的源代,几乎CMap所有的内部参数传递都是访问ARG_KEYARG_VALUE,因 此,使用KEY&来代替ARG_KEY似乎是正确的,除了在些情况下:

1 简单的数据型,如int ,char值传递与参数传递没有什不同

2 如果用CStringKEY,你应该LPCTSTR   ARG_KEY而非CString&,接下来我讨论原因。

如何CMap类为自己工作

好的,就我前面说过的,CMap是一个哈西表,一个哈西表要有哈西“——一个UINT型,用哈西在哈西表中的序数。如果有更多的相同的关键字,他成一个表。因此,你应该首先构造哈西函数。

CMap用摸板函数HashKey()来构造哈西函数。缺省用和版的LPCSTRLPCWSTR如下:

 

  // inside <afxtemp.h>
template<class ARG_KEY>
AFX_INLINE UINT AFXAPI HashKey(ARG_KEY key)
{
    // default identity hash - works for most primitive values
    return (DWORD)(((DWORD_PTR)key)>>4);
}

// inside <strcore.cpp>
// specialized implementation for LPCWSTR
#if _MSC_VER >= 1100
template<> UINT AFXAPI HashKey<LPCWSTR> (LPCWSTR key)
#else
UINT AFXAPI HashKey(LPCWSTR key)
#endif
{
    UINT nHash = 0;
    while (*key)
        nHash = (nHash<<5) + nHash + *key++;
    return nHash;
}

// specialized implementation for LPCSTR
#if _MSC_VER >= 1100
template<> UINT AFXAPI HashKey<LPCSTR> (LPCSTR key)
#else
UINT AFXAPI HashKey(LPCSTR key)
#endif
{
    UINT nHash = 0;
    while (*key)
        nHash = (nHash<<5) + nHash + *key++;
    return nHash;
}

 

正如你所见到的,缺省行为是假定关键字是一个指针,并且转变成DWORD类型,这就是为什么会出现“error C2440:’type cast’:cannot convert from ‘ClassXXX’to ‘DWORD_PTR’”如果你不提供一个特别的HashKey()函数给你的类就会出现上述情况。

并且由于MFC仅仅提供了特殊的工具LPCSTRLPCWSTR,却没有提供CStringACStringW,如果你想要在CMap中用CString,就必须声明CMap<CString ,LPCSTR….>,

 

OK,现在你知道怎么计算CMap的哈西值了,但是因为一个关键字可能对应多个哈西值,CMap就需要找遍整个链表来找到正确的摸板,不仅用同样的哈西值。当CMap不匹配时,就会访问CompareElements(),一个摸板方程

 

// inside <afxtemp.h>
// noted: when called from CMap,
//        TYPE=KEY, ARG_TYPE=ARG_TYPE
// and note pElement1 is TYPE*, not TYPE
template<class TYPE, class ARG_TYPE>
BOOL AFXAPI CompareElements(const TYPE* pElement1,
                            const ARG_TYPE* pElement2)
{
    ASSERT(AfxIsValidAddress(pElement1,
           sizeof(TYPE), FALSE));
    ASSERT(AfxIsValidAddress(pElement2,
           sizeof(ARG_TYPE), FALSE));

    // for CMap<CString, LPCTSTR...>
    // we are comparing CString == LPCTSTR
    return *pElement1 == *pElement2;
}

 

 

因此,如果你想在自己的类中用CMap,你不得不重写HashKey()CompareElements()

结束语

1 CMap是一个哈西表,而STL::map是一个树表,对他们做比较是没有意义的。但是,如果你要重新找到有序的关键字,你就得使用STL::map

2 HashKey()的设计是高效的。你应该提供一个较少冲突的HashKey(),并且容易计算。你要记注,对于有些类来说,这不容易。

3 当用Cmap(或STL::hash_map,要注意哈西表的大小。

猜你喜欢

转载自blog.csdn.net/dengrk/article/details/1947304