Map 容器的键值如果是 C++ 内置数据类型, Map 在构造底层的红黑树时会用到这些内置类型的 < 操作来进行元素间的比较操作。
但是当 Map 容器的键值不是内置类型而是自己定义的类型时,比如一个类、一个结构体。此时就要对 Map 的比较函数做一点处理,这种情况还会有两种情况出现:
第一种即为如果 Map 的键值是类的对象是,由于类模板是静态编译的,如果自己定义的 Map 键值没有实现 “ < ” 操作符,编译会出错。此时可以定义类的成员函数 bool operator < ( const NodeInfo& rValue ) const(注意了这个const不能少)。这样在构造 Map 的红黑树及针对 Map 进行 find 操作时会自动调用到这个自己重载的“ < ”操作。
第二种情况即为如果 Map 的键值是类对象的指针时,由于编译器把指针当作 32 位的整数来处理,此时会存在潜在的错误:不管你自己定义的类中重载了“ < ”操作符与否,编译都会通过,因为它把指针当作 32 位整数来看待。但是在针对 map 进行 find 操作时不会找到自己想要的结果。此时必须实现自己的比较函数对象,不能再用 Map 默认的比较函数对象了,比如下面的比较函数对象:
class Compare : public std ::binary_function <NodeInfo *,NodeInfo *,bool >
{
public :
bool operator ()( const NodeInfo * plValue , const NodeInfo * rValue )
{
return plValue ->addr .union_addr_mem .dwAddr < rValue ->addr .union_addr_mem .dwAddr ;
}
};
std ::map <NodeInfo *,int ,Compare > m_mapList ;
这个 map 类的键值为 NodeInfo * ,值域为 int ,比较函数为 Compare 。
针对 std::find() 同 std::find_if() 的区别,它们的源码如下所示:
_InIt _Find(_InIt _First, _InIt _Last, const _Ty& _Val)
{ // find first matching _Val
_DEBUG_RANGE(_First, _Last);
for (; _First != _Last; ++_First)
if (*_First == _Val)
break;
return (_First);
}
_InIt _Find_if(_InIt _First, _InIt _Last, _Pr _Pred)
{ // find first satisfying _Pred
_DEBUG_RANGE(_First, _Last);
_DEBUG_POINTER(_Pred);
for (; _First != _Last; ++_First)
if (_Pred(*_First))
break;
return (_First);
}
Find() 和 find_if() 都是到指定的容器中查找指定的元素。它们在比较元素相同时有不同之处, find() 通过“ == ”操作符进行比较, find_if() 则通过模板参数给定的比较函数对象进行比较。这就说明在你自己的类中要重载 == 操作符,如果你用 find() 的话,重载 operator() 操作符,如果你用 find_if() 的话。
如果容器中存的是对象的指针,想用 find() 函数来搜索容器中的元素,由于 == 号的左操作数不是这个类的对象,必须声明友元函数来比较它们(下面说明重载操作符在什么情况下使用友元,什么情况下使用类成员函数)。如下所示:
friend bool operator == ( const NodeInfo * plValue , const NodeInfo & rValue )
{
return plValue ->addr .union_addr_mem .dwAddr == rValue .addr .union_addr_mem .dwAddr ;
}
当使用 find_if() 进行操作时,则要根据容器中所存放的内容来定义 operator() 操作符。例如:
bool operator () (const NodeInfo rValue )
{
return addr .union_addr_mem .dwAddr == rValue .addr .union_addr_mem .dwAddr ;
}
bool operator () (const NodeInfo * rValue )
{
return addr .union_addr_mem .dwAddr == rValue ->addr .union_addr_mem .dwAddr ;
}
什么时候定义类成员操作符重载,什么时候定义非类成员操作符重载?
答:( 1 )如果一个重载操作符是类成员,那么只有当跟它一起使用的左操作数是该类对象时, 它才会被调用,如果该操作符的左操作数必须是其他类型,那么重载操作符必须是非类成员操 作符重载。
(2 ) C++ 要求,赋值( = ),下标 ( [ ] ),调用( () )和成员访问箭头( -> )操作符必须被指定为类成员操作符,否则错误。