4.6 案例10 使用QList处理数据集

article/2025/10/9 22:23:30

本案例对应的源代码目录:src/chapter04/ks04_06。

本节介绍Qt的数据处理类QList。如果要使用QList,需要包含其头文件<QList>。本案例也设计了三种编程场景对QList的使用进行介绍。

(1)向QList中添加成员并遍历。

(2)向QList中添加自定义类的对象。

(3)向QList中添加自定义类对象的指针。

下面进行详细介绍。

1.向QList中添加成员并遍历

代码清单4-44中介绍了向QList中添加成员并遍历的方法,这里也使用quint16作为成员对象的类型。

代码清单4-44

void example01(){                       

    // 添加成员

    QList<quint16> lstObj;

    lstObj.push_back(2011);

    lstObj.push_back(2033);

    lstObj.push_back(2033);

    lstObj.push_back(2042);

    lstObj.push_back(2045);

    // push_front

    lstObj.push_front(2046);

    ...

}

向QList中添加成员也用到了push_back()。接下来使用几种不同的方法对QList行遍历。为了方便,把遍历、打印QList的代码封装为几个接口,以便在其他案例中使用,如代码清单4-45所示。在标号①处,因为传入的参数类型是const引用,所以在printByIterator()接口实现代码中的标号②处,需要使用QList<quint16>::const_iterator定义常量迭代器对象iteList来访问QList。为iteList赋值时需要调用lstObj对象的constBegin()接口,在判断QList首尾时使用QList的constBegin()、constEnd()接口。同理,在标号④处的倒序访问接口中,用QList<quint16>::const_reverse_iterator定义迭代器对象,并且在标号⑤处用的是QList的crbegin()、crend()接口获取QList的倒序首尾。

代码清单4-45

void example01(){

    ...

    // 遍历成员-使用下标

    printByIndex(lstObj);

    // 遍历成员-使用迭代器(正序)

    printByIterator(lstObj);

    // 遍历成员-使用迭代器(倒序)

    printByIteratorReverse(lstObj);

    ...

}

// 遍历成员-使用正序迭代器

void printByIterator(const QList<quint16>& lstObj) {                            

    cout << endl << "-------------- QList ---------------" << endl;

    cout << "print members using iterator......" << endl;

    QList<quint16>::const_iterator iteList = lstObj.constBegin();               

    for (iteList = lstObj.constBegin(); iteList != lstObj.constEnd(); iteList++) {

        cout << "    " << *iteList << endl;

    }

}

// 遍历成员-使用倒序迭代器

void printByIteratorReverse(const QList<quint16>& lstObj){

    cout << endl << "-------------- QList ---------------" << endl;

    cout << "print members using iterator reverse......" << endl;

    QList<quint16>::const_reverse_iterator iteList;                               

    for (iteList = lstObj.crbegin(); iteList != lstObj.crend(); iteList++){                                                                       

        cout << "    " << *iteList << endl;

    }

}

// 遍历成员-使用下标

void printByIndex(const QList<quint16>& lstObj){

    cout << endl << "-------------- QList ---------------" << endl;

    cout << "print members using index......" << endl;

    int idxList = 0;

    for (idxList = 0; idxList < lstObj.size(); idxList++) {

        cout << "    lstObj[" << idxList << "] =" << lstObj[idxList] << endl;

    }

}

2.向QList中添加自定义类的对象

向QList中添加自定义类的对象时使用CMyClass类,方法同QVector用法类似,见代码清单4-46。

代码清单4-46

void example02(){

    // 添加成员

    QList<CMyClass> lstObj;

    CMyClass myclass1(2011, "lisa");

    CMyClass myclass2(2012, "mike");

    CMyClass myclass3(2012, "mike");

    CMyClass myclass4(2013, "john");

    CMyClass myclass5(2013, "ping");

    CMyClass myclass6(2025, "ping");

    // 如果想让下面的语句编译通过并且按照预期执行,需要为CMyClass类提供拷贝构造函数

    lstObj.push_back(myclass1);                                                     

    lstObj.push_back(myclass2);

    lstObj.push_back(myclass3);

    lstObj.push_back(myclass4);

    lstObj.push_back(myclass5);

    lstObj.push_back(myclass6);

    // 遍历成员

    cout << endl << "-------------- QList ---------------" << endl;

    cout << "print members using idx......" << endl;

    int idxList = 0;

    for (idxList = 0; idxList < lstObj.size(); idxList++) {

        cout << "    lstObj[" << idxList << "] : id = "

             << lstObj[idxList].getId() << ", name = "

             << lstObj[idxList].getName().toLocal8Bit().data() << endl;

    }

     // 查找

    cout << endl << "-------------- QList ---------------" << endl;

    cout << "begin find member in QList......" << endl;

    CMyClass myclassx(2013, "john");

    QList<CMyClass>::iterator iteList = std::find(lstObj.begin(), lstObj.end(), myclassx);

    if (iteList != lstObj.end()) {

        cout << "find myclassx in list." << endl;

    }

    else {

        cout << "cannot find myclassx in list" << endl;

    }

}

代码清单4-46中需要注意的是标号①处的lstObj.push_back(myclass1),这句代码要求CMyClass类提供拷贝构造函数。其实如果不写CMyClass类的拷贝构造函数,程序也能构建成功,因为编译器会为CMyClass类提供默认的拷贝构造函数。尝试一下封掉CMyClass的拷贝构造函数,看看是否能将项目构建成功。其实,封掉CMyClass的拷贝构造函数后,push_back()可以成功调用,但是程序却会出现运行时异常。这是为什么呢?因为编译器提供的默认拷贝构造函数仅仅执行按位复制,也就是将对象的成员变量的值一对一复制,而CMyClass类的成员中有指针,如果按位复制那么就不会为指针变量重新申请内存而是将它和被复制对象指向同一块内存。在CMyClass析构时会出现将同一块内存多次delete的问题,导致出现异常。所以,在本案例中应该为类编写显式的拷贝构造函数。

另外,因为在实现查找功能时用到了std::find(),所以仍然需要为CMyClass类重载operator==操作符。尝试封掉类CMyClass的operator==的重载操作符的定义和实现代码,看看会有什么结果。哈哈,编译器会报错。

error C2678: 二进制“==”: 没有找到接受“CMyClass”类型的左操作数的运算符(或没有可接受的转换)。

编译器明确提示需要为CMyClass提供operator==的重载,所以如果要使用std::find(),那么对类的operator==操作符的重载是不可缺少的。

3.向QList中添加自定义类对象的指针

向QList中添加自定义类对象的指针与QVector的案例类似,见代码清单4-47。

代码清单4-47

void example03() {

    // 添加成员

    QList<CMyClass*> lstObj;

    CMyClass* pMyclass1 = new CMyClass(2011, "lisa");

    CMyClass* pMyclass2 = new CMyClass(2012, "mike");

    CMyClass* pMyclass3 = new CMyClass(2012, "mike");

    CMyClass* pMyclass4 = new CMyClass(2013, "john");

    CMyClass* pMyclass5 = new CMyClass(2013, "ping");

    CMyClass* pMyclass6 = new CMyClass(2025, "ping");

    // 无须为CMyClass类提供拷贝构造函数

    lstObj.push_back(pMyclass1);

    lstObj.push_back(pMyclass2);

    lstObj.push_back(pMyclass3);

    lstObj.push_back(pMyclass4);

    lstObj.push_back(pMyclass5);

    lstObj.push_back(pMyclass6);

    // 遍历成员

    cout << endl << "-------------- QList ---------------" << endl;

    cout << "print members in custom defined class using idx......" << endl;

    int idxList = 0;

    for (idxList = 0; idxList < lstObj.size(); idxList++) {

        cout << "    lstObj[" << idxList << "] : id = "

             << lstObj[idxList]->getId() << ", name = "

             << lstObj[idxList]->getName().toLocal8Bit().data() << endl;

    }

    // 退出前要释放内存

    // 方法1,使用下标遍历

    cout << endl << "-------------- QList ---------------" << endl;

    cout << "desctruct members before exit......" << endl;

    idxList = 0;

    for (idxList = 0; idxList < lstObj.size(); idxList++) {

        cout << "    deleting " << idxList << ", id = "

             << lstObj[idxList]->getId() << ", name = "

             << lstObj[idxList]->getName().toLocal8Bit().data() << endl;

        delete lstObj[idxList];

    }

    // 方法2,使用迭代器遍历                                                  ①

    //QList<CMyClass*>::iterator iteList = lstObj.begin();

    //for (iteList = lstObj.begin(); iteList != lstObj.end(); iteList++, idxList++) {

    //    if (NULL != *iteList) {

    //        delete *iteList;

    //    }

    //}

    lstObj.clear();

}

代码清单4-47中的标号①处,方法2的代码被封掉的原因也是因为防止重复析构。此处给出方法2是为了演示用迭代器的方式遍历列表的成员。

本节介绍了QList的用法,它跟QVector有很多相似的地方。不同之处在于,如果对性能要求更高一些,应考虑QVector。

----------------------------------------------------------------------------------------------------------------------------------------------

《Qt 5/PyQt 5实战指南》目录


http://chatgpt.dhexx.cn/article/2yOJRoVY.shtml

相关文章

Qt· 常用容器之QList

目录 1、QList介绍 2、构造函数 3、插入函数 4、删除和移动类函数 5、访问和查询函数 6、替换、移动和交换函数 7、运算符函数 8、迭代器函数 9、容器类型转换函数 其他内容 1、QList介绍 在开始讲解 QList 之前&#xff0c;我们先明确一下 Qt 数据容器能存储什么&a…

QT QList<T>介绍与应用、详解、使用说明、官方手册翻译

文章目录 1. 简介2. 使用示例3. 官方手册4. Member Function Documentation 1. 简介 QList<T>是目前最常用的容器类 。它存储了给定类型的值的一个列表&#xff0c;而这些值可以通过索引访问。在内部&#xff0c;QList使用数组来实现&#xff0c;一确保进行快速的基于索…

Web后端开发入门(3)

在Eclipse中创建web项目 右键->new->Project->Web->Dynamic Web Project->下一步 Project name&#xff1a;给你的web项目起一个名称 Target runtime:你这个项目运行在哪一个web服务器上。点击New runtime&#xff0c;选择自己安装的服务器&#xff0c;然后点击…

【Delphi + Vue】Web后端动态图片传递给前端

在用Delphi做Web后台的时&#xff0c;有时需要用到后台动态生成二维码图片&#xff0c;给前端使用&#xff0c;虽然前端可以通过js库生成&#xff0c;目前流行的有 QR码生成器&#xff08;在线&#xff09;、QRCode.js&#xff08;支持本地&#xff09;、 arale-qrcode&#xf…

web搭建服务器端+创建web后端项目操作步骤

一、搭建服务器端 以前,我们的iava程序都是在本地运行,在idea执行main&#xff08;&#xff09;开始运行; 从javaEE开始,后端程序都是运行在服务器上,准备工作就是先要在我们的电脑上安装一个web服务器,把我们开发的java程序部署在服务器中,这样就可以从前端远程的通过网络进行…

从Web后端(Java)转到游戏服务端的感受

九零后的男生几乎都是玩电子游戏长大的&#xff0c;做游戏开发几乎是每个九零后男生从小就有的梦想吧。我的大学时代&#xff0c;正好与移动Web高速发展的时代重合了&#xff0c;大学里几乎所有同学都是做Web方向的开发&#xff0c;Web前端&#xff0c;Java后端等等。大四的秋招…

Python web后端开发框架 Django 、Flask、Tornado

深入学习Python &#xff0c;用Django做Web后端开发现在Python的用途愈来愈广&#xff0c;服务器、Web、游戏、爬虫、数据分析 以及人工智能 学习之路还很长技术之路 不能回头 陷进去 就出不来 就跟恋爱一般&#xff0c;学习中、项目中 印象笔记、有道云笔记、Onenote都记了好…

Web后端框架Springboot创建和基础讲解(一)

Springboot是一款底层由java编写的web后端框架&#xff0c;前身是spring框架&#xff0c;相较于前身框架而言&#xff0c;继承了其良好的兼容性以及扩展性&#xff0c;并且舍弃了大量繁杂的xml文件&#xff0c;将其改为依赖注入spirngboot框架的容器中&#xff0c;节省了工作者…

Web后端开发知识点整理

Web后端开发知识点整理 九大内置对象 1:为了方便开发者而在jsp页面加载完毕时而自动创建的内置对象 内置对象名 类型 request HttpServletRequest response HttpServletResponse config ServletConfig application ServletContext sessi…

wed后端和java的区别_web前端和web后端的区别详细分析

原标题&#xff1a;web前端和web后端的区别详细分析 在刚开始从事web开发时&#xff0c;首先要选准学习方向&#xff0c;看是想从事前端部分还是后端程序部分。当然在工作的后期&#xff0c;就不会分的那么细致了。做前端到后期也会懂一些后端的技术&#xff0c;反之&#xff0…

web搭建服务器端+创建web后端项目详细步骤

一、搭建服务器端 Web服务器&#xff1a;用于响应来自Web客户端&#xff08;如浏览器、移动应用程序等&#xff09;的请求并提供Web页面和其他Web资源的软件程序或计算机系统。它允许用户在Web浏览器中输入网址&#xff0c;通过HTTP协议向服务器发送请求&#xff0c;并收到Web页…

我的 Java/C# web 后端开发技术选择

简单介绍一下&#xff0c;我的 Java/C# web 后端开发技术选择。与网上一般人所用&#xff0c;大不相同。 先来一个表格&#xff0c;以下是我常用的Java/C# web 后端开发技术&#xff1a; 我常用的Java/C# web 后端开发技术 技术分类Java webC# web数据库bonecp,commons-dbcp,co…

php后端技术 有哪些,web后端开发技术有哪些 ?

如果你想要从事web后端开发的工作&#xff0c;那么你就需要了解web后端技术有哪些&#xff1f;并且要学习掌握这些web后端开发技术。下面我们就给大家介绍有哪些web后端技术。 web后端开发技术&#xff1a; 1、脚本语言基础。主流的后端脚本语言有php、 java 、 python、C、C等…

web后端开发php,web后端开发主要做什么?

应用程序或web服务可以分为两大部分:前端和后端。从这些名字可以猜出他们的角色。前端是你可以“看到”的部分。它是让你与应用程序或服务交互的部分。颜色、动画、布局以及所有其他增加你使用应用或网站体验的酷东西就是前端。前端通常称为用户界面(UI)。后端是你看不到的部分…

Web后端基础知识

文章目录 前言一、web基础知识1.web开发使用java的优势2.web前后端分离有什么好处&#xff1f;谈一下各自的职责。3.POJO和Java Bean&#xff1f;4.Tomcat容器(应用服务器)谈一下&#xff1f;5.Servlet谈一下&#xff1f;6.Servlet的生命周期谈一下&#xff1f;7.Servlet的三大…

web后端(javaWeb)

文章目录 1.javaweb简介2.XML3.Tomcat服务器4.Servlet15.1协议互联网通信模型5.2HTTP6.servlet27.JDBC8.JSP9.JSP中的文件下载和上传10.请求重定向和请求转发的区别11.Cookie 和 Session12.谷歌验证码的使用13.Filter过滤器14.ThreadLocal 的使用15.JSON和Ajax请求15.1JSON 在 …

GIMP基本功能和教程!

以剪贴板为内容创建一个工作布&#xff1a;SHIFT CTRL &#xff36; 或者&#xff1a;File -> Create ->From Clipboard 取消选择&#xff1a;SHIFT CTRL A 或者&#xff1a;Select -> None 反选&#xff08;选补集&#xff09;&#xff1a;CTRL I 或者&#xff…

GIMP教程 4 图层

图层可以说是现代制图软件的精髓&#xff0c;也是最根本地区别于纸质制图的地方。 GIMP呼出图层窗口的方法也很简单 点击【窗口----可停靠对话框----图层】 或者直接使用快捷键 ctrlL 便可呼出图层窗口 剩下的&#xff0c;就跟所有其它制图软件一样了。 还有问题可联系作者…

GIMP教程 5 选择

选择的意义在于限制作用范围&#xff0c;即&#xff0c;使所有操作只对选择部分有效&#xff0c; 不会“误伤”未选择部分。 gimp提供了多种选择工具&#xff0c;参见工具箱前几个按钮&#xff0c; 或者 【工具----选择工具】中按钮列表。 使用左键拖出选择范围&#xff0c…