Qt之QMap自定义数据类型(Struct)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_25034451/article/details/86471398

关于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->name<item.name){
            return true;
        }
        if(this->address<item.address){
            return true;
        }
        if(this->value<item.value){
            return true;
        }
        return false;
    }

测试结果通过。

若有疑问可以在下方留言,欢迎关注我的公众号CodingBL。
CodingBL

猜你喜欢

转载自blog.csdn.net/qq_25034451/article/details/86471398