关于QMap使用自定义类型
在QMap中,Map的key是可以使用struct的,但是使用时会报如下的错误
D:\Qt\Qt5.7.0\5.7\mingw53_32\include\QtCore\qmap.h:74: error: no match for 'operator<' (operand types are 'const Item' and 'const Item')
return key1 < key2;
^
原因分析
struct Item {
QString name;
QString address;
QChar value;
};
QMap<Item,QString> maps;
Item item;
item.name = "张三";
item.value = 0xf013;
item.address = "地址1";
Item item1;
item1.name = "李四";
item1.value = 0xf012;
item1.address = "地址2";
maps.insert(item,"这是张三");
maps.insert(item1,"这是李四");
以上是示例代码
异常很简单,没有重载<运算符,重载即可。
对struct重新定义如下:
struct Item {
QString name;
QChar value;
bool operator < ( const Item& item) const
{
QString name;
QString address;
QChar value;
bool operator < ( const Item& item) const
{
return this->name<item.name&&this->value<item.value&&this->address<item.address;
}
};
编译通过。
继续测试
QMap<Item,QString> maps;
Item item;
item.name = "张三";
item.value = 0xf013;
item.address = "地址1";
Item item1;
item1.name = "李四";
item1.value = 0xf012;
item1.address = "地址2";
maps.insert(item,"这是张三");
maps.insert(item1,"这是李四");
QMap<Item,QString>::const_iterator var;
int i = 0;
for (var = maps.constBegin(); var !=maps.constEnd(); ++var,i++) {
qDebug()<<var.key().name;
qDebug()<<var.key().value;
qDebug()<<var.value();
}
结果
"张三"
'00\uf013'
"这是李四"
0
没错,这就是结果,与想象的不同,值被覆盖了。
继续原因分析
在struct中,重载==运算符
bool operator < ( const Item& item) const
{
return this->name<item.name&&this->value<item.value&&this->address<item.address;
}
bool operator == ( const Item& item) const
{
qDebug()<<"=="<<(this->name<item.name&&this->value<item.value&&this->address<item.address);
return this->name<item.name&&this->value<item.value&&this->address<item.address;
}
运行结果:
"张三"
'00\uf013'
"这是李四"
0
并没有打印= =运算符的使用,意味着 = =没有使用,QMap中没有使用==运算符。
第一次测试
对struct加入如下代码,删除= =运算符的相关代码
bool operator < ( const Item& item) const
{
qDebug()<<this->name;
qDebug()<<item.name;
qDebug()<<"this->name<item.name"<<(this->name<item.name);
qDebug()<<"this->value<item.value"<<(this->value<item.value);
qDebug()<<"this->address<item.address"<<(this->address<item.address);
qDebug()<<(this->name<item.name&&this->value<item.value&&this->address<item.address);
return this->name<item.name&&this->value<item.value&&this->address<item.address;
}
结果如下:
"张三"
"李四"
this->name<item.name true
this->value<item.value false
this->address<item.address true
false
"李四"
"张三"
this->name<item.name false
this->value<item.value true
this->address<item.address false
false
"张三"
'00\uf013'
"这是李四"
0
重载函数运行了两次,并且结果都为false;第一次与第二次的参数交换了位置;
第二次测试
将以上代码修改,item.value交换位置。
QMap<Item,QString> maps;
Item item;
item.name = "张三";
item.value = 0xf012;
item.address = "地址1";
Item item1;
item1.name = "李四";
item1.value = 0xf013;
item1.address = "地址2";
maps.insert(item,"这是张三");
maps.insert(item1,"这是李四");
QMap<Item,QString>::const_iterator var;
int i = 0;
for (var = maps.constBegin(); var !=maps.constEnd(); ++var,i++) {
qDebug()<<var.key().name;
qDebug()<<var.key().value;
qDebug()<<var.value();
qDebug()<<i;
}
结果如下:
"张三"
"李四"
this->name<item.name true
this->value<item.value true
this->address<item.address true
true
"张三"
'00\uf012'
"这是张三"
0
"李四"
'00\uf013'
"这是李四"
1
结果解析
原来QMap中通过<运算符来比较两个参数是否相等
即通过a<b来判断是否相等,若小于成立,则说明不相等,便会插入;
若小于不成立,则说明要么大于,要么等于;
然后再反过来比较一次,即b<a,若这次小于成立,则b>a,则说明它们不相等,便会插入,否则相等。
打开源码查看
template <class Key, class T>
Q_INLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::insert(const Key &akey, const T &avalue)
{
detach();
Node *n = d->root();
Node *y = d->end();
Node *lastNode = Q_NULLPTR;
bool left = true;
while (n) {
y = n;
if (!qMapLessThanKey(n->key, akey)) {
lastNode = n;
left = true;
n = n->leftNode();
} else {
left = false;
n = n->rightNode();
}
}
if (lastNode && !qMapLessThanKey(akey, lastNode->key)) {
lastNode->value = avalue;
return iterator(lastNode);
}
Node *z = d->createNode(akey, avalue, y, left);
return iterator(z);
}
函数中的两次qMapLessThanKey证明了猜想正确。
解决方法
那么该如何解决此问题?在函数中使用&&符号是错误的方式,改变如下:
bool operator < ( const Item& item) const
{
if(this->text.compare(item.text)!=0){
return this->text<item.text;
}
if(this->what.compare(item.what)!=0){
return this->what<item.what;
}
return this->icon<item.what;
}
测试结果通过。
若有疑问可以在下方留言,欢迎关注我的公众号CodingBL。