开始之前,先看一下std::map的模板声明:
template<
class Key,
class T,
class Compare = std::less<Key>,
class Allocator = std::allocator<std::pair<const Key, T> >
> class map;
通常情况下,我们这样定义并且使用map
std::map<int, int> map;
map.insert({1,2});
如下,现在我们用自己定义的类类型作为key
#include <iostream>
#include <map>
class Dylan
{
public:
Dylan() { name = ""; addr = ""; }
Dylan(std::string na, std::string ad) : name(na), addr(ad) {};
const string getName() const { return name; }
const string getAddr() const { return addr; }
private:
std::string name;
std::string addr;
int age = 0;
};
int main()
{
std::map<Dylan, int> map;
Dylan dy("111","222");
map.insert({dy,1}); //这句会引发编译时的错误,如果没有这句插入操作,则在vs环境下可编译通过
}
我们将收到编译错误:
以vs2019 环境为例,上面的代码会收到如下error:
error C2676: binary '<': 'const _Ty' does not define this operator or a conversion to a type acceptable to the predefined operator
这是什么原因呢?这是由于map的底层数据结构决定的,map的底层结构是一棵红黑树,为有序结构;所以在向map中插入数据的时候需比较插入数据的大小,也就是说需要待插入数据支持比较大小。
要让class Dylan类的对象支持比较大小,有两种方法:
方法一 在类中重载小于号运算符(<)
class Dylan
{
public:
Dylan() { name = ""; addr = ""; }
Dylan(std::string na, std::string ad) : name(na), addr(ad) {};
const string getName() const { return name; }
const string getAddr() const { return addr; }
bool operator<(const Dylan& dy1) const { return this->getName() < dy1.getName(); }
//重载小于号运算符,注意切记函数声明为const类型
private:
std::string name;
std::string addr;
int age = 0;
};
在这里有个要注意的地方,就是重载小于号的函数必须声明为const函数,否则会收到如下error:
error C2678: binary '<': no operator found which takes a left-hand operand of type 'const _Ty' (or there is no acceptable conversion)
message : while compiling class template member function 'bool std::less<_Kty>::operator ()(const _Ty &,const _Ty &) const'
map默认提供一个仿函数,用来比较带插入元素的大小,如果不自定义指定,map就会在std::less中调用待插入元素自己的小于号运算符去比较大小,由于std::less元素是const函数,所以我们自己在实现重载小于号运算符时,也要记住将函数声明为const类型。std::less是const的是由map的构造函数声明决定的,他的构造函数的第三个参数,要求传入一个比较大小的函数指针,这个参数是const参数(即const函数)
方法二 自定义less函数
class Dylan {.....}
class myless_than
{
public:
bool operator()(const Dylan& dy1, const Dylan& dy2) const//也得是const的
{
return dy1.getName() < dy2.getName();
}
};
int main()
{
std::map<Dylan, int, myless_than> map;
Dylan dy("1111","2222");
map.insert({dy,1});
}
注意,重载()运算符的函数也得是const的,原因和方法一中的原因类似,否则会受到如下error:
error C3848: expression having type 'const myless_than' would lose some const-volatile qualifiers in order to call 'bool myless_than::operator ()(const Dylan