STL容器-- list的模拟实现(附源码)
STL容器-- list的模拟实现(附源码)
List的实现主要考察我们对list这一容器的理解,和代码的编写能力,通过上节对list容器的使用,我们对list容器已经有了一些基本的了解·,接下来就让我们来实现一些list容器常见的功能函数来加深我们对c++工程的理解:

一、基本框架的搭建
首先我们需要将基本的框架搭建好, 从之前我们学数据结构时,对list的一些认识并结合c++ stl标准可以得出:
- 定义节点的构造
- 明确指针的指向
- list的封装
根据c++中的标准我们可以得知,list时一个双向迭代器, 所以对应的, 我们需要定义的双向循环链表:
1.1节点的构造
template <class T>
struct ListNode
{T _data;ListNode<T>* _next;ListNode<T>* _prev;// 节点的构造函数ListNode(const T& val):_data(val),_next(nullptr),_prev(nullptr){}
};
在定义一个节点的时候,我们先让这个节点的_next and _prev指针为空
1.2 list的封装
template <class T>
struct ListNode
{T _data;ListNode<T>* _next;ListNode<T>* _prev;// 节点的构造函数ListNode(const T& val = T()):_data(val),_next(nullptr),_prev(nullptr){}
};template<class T>
class list
{
public:typedef ListNode<T> node;void empty_init(){// zdl :: 在初始化一个空链表时, 先定义一个哨兵位_head = new node();_head->_next = _head;_head->_prev = _head;}list(){empty_init();}// functon define:}private:node* _head;
};
同时为了防止访问冲突,我们可以将我们自己实现的类,放在我们自己定义的命名域中:
namespace zdl
{template <class T>struct ListNode{T _data;ListNode<T>* _next;ListNode<T>* _prev;// 节点的构造函数ListNode(const T& val):_data(val),_next(nullptr),_prev(nullptr){}};template <class T>struct ListNode{T _data;ListNode<T>* _next;ListNode<T>* _prev;// 节点的构造函数ListNode(const T& val = T()):_data(val),_next(nullptr),_prev(nullptr){}};template<class T>class list{public:typedef ListNode<T> node;void empty_init(){// zdl :: 在初始化一个空链表时, 先定义一个哨兵位_head = new node();_head->_next = _head;_head->_prev = _head;}list(){empty_init();}// functon define:}private:node* _head;};
}
这样list的基本框架就搭建好了!!
二、节点的尾插和头插
2.1 节点的头插 (push_back)

通过前面数据结构的学习。我们已经清楚了链表的结构,在进行数据尾插时, 就只是在改变指针的指向罢了:
void push_back(const T& val){node* creat = new node(val);node* tail = _head->_prev;tail->_next = creat;creat->_prev = tail;creat->_next = _head;_head->_prev = creat; }
2.2 节点的头插(push_front)
节点的头插和尾插十分的相似,
这里我们就直接展示一下代码:
void push_front(const T& val){node* fnode = new node(val);fnode->_next = _head->_next;fnode->_prev = _head;_head->_next->_prev = fnode;_head->_next = fnode;}
2.3 数据插入验证
为了方便起见, 我这里再再这个类里面定义一个打印链表的函数:
void Print_list(){node* cur = _head->_next;while (cur != _head){cout << cur->_data << " ";cur = cur->_next;}cout << endl;}
完成了list容器的头插和尾插操作接下来我们可以来验证一下,我们的函数实现是否有问题:
#include"list.h"int main()
{zdl::list<int> l1;l1.push_back(1);l1.push_back(2);l1.push_front(3);l1.Print_list();return 0;
}
通过运行可知, 这里的函数没有问题:

三、list迭代器的实现
list迭代器的功能和vetor的功能有很多相似的地方,但是二者在底层实现时,使用的不同的方法:
基于,list迭代器的特殊性质,我们会采用类封装的方式来满足list_iterator的特殊性质:
3.1迭代器基本功能的实现和封装处理
template<class T>struct list_iterator{typedef ListNode<T> node;typedef list_iterator<T> self;node* _nd;list_iterator(node* nd):_nd(nd){}// zdl:: 实现迭代器的基本功能:// 解引用数值T& operator*(){return _nd->_data;}// zdl:: 前置++ / --self& operator++(){_nd = _nd->_next;return *this;}self& operator--(){_nd = _nd->_prev;return *this;}// zdl:: 后置 ++ / --self operator++(int){self tmp = _nd;_nd = _nd->_next;return tmp;}self operator--(int){self tmp = _nd;_nd = _nd->_prev;return tmp;}// zdl:: != 运算bool operator!=(const self& s){return _nd != s._nd;}};
实现了list_iterator的功能后,我们就只需要将他封装道list类中就可以正常使用了:


基本的逻辑都是十分的简单的接下来我们来简单的验证一代码是否可行:

3.2 对结构体(类)的解引用
对
->运算符的重载
大家现在可以想象一下这样的场景,假设我现在在llist中存储的不是基础类型的元素,而是类等较为复杂的对象时,我们应当怎么正常的使用这个类对象的成员呢?
这时,我们就可以考虑对->运算符重载, 通过返回对象的地址,来访问成员变量和成员函数等!
下面我们就来举个例子:
假设我现在我要在list中存储pos类:
struct pos
{int row;int col;//构造函数pos(const int& x = 0, const int& y = 0):row(x),col(y){}//成员函数void pos_show(){printf("(%d, %d) ",row, col);}
};
我们就只需要重载->运算符:
T* operator->()
{return &_nd->_data;
}
运行后可以得到:

但是大家可能会觉得很奇怪,通过->重载,返回的只是_data的地址,为什么能直接访问到元素呢?不应该使用it->->解引用两次才行啊?
这个其实就只是c++便准下为我们提供的特殊语法, 通过这样的规定使我们能够直接访问到元素, 当然c++也是支持这样的写法的:

但是不支持这样的写法:

3.3const迭代器的实现与模板参数的巧用
前面我们已经实现了,可读可写的迭代器,现在我们就来实现一下只读迭代器:
const iterator,
其实从功能上看,这个迭代器与原来的迭代器十分的相似,只是不能对指向对象的值进行修改,因此我们就只需要对* 和 ->运算符重载的时候稍加修改就可以得到我们想要的结果,即再创建一个类:

其他的共同功能粗需要改动,只需要改动下面两个重载函数:
const T& operator*()
{return _nd->_data;
}
const T* operator->()
{return &_nd->_data;
}
紧接着我们还需要在llist类中实现const对象专用的begin()、end()


接下来我们来验证一下效果:

现在consr iterator也实现好了,但是这里依然还存在问题,这样我们将相当于为迭代器实现了两个类,这两个类的攻击能还高度重合,这并没有,体现出模板函数的简洁性,因此我们还可以通过其他的方式来优化我们现在的代码。
通过对源码的分析,参照我们或许可以从中得到一些启发, 从源码中可知我们可以得知,通过对模板参数的巧用就可以的实现代码的简化:

接下来我们就只需要将代码稍加改动就可以实现我们的目的:


接下来,我们再次运行看看是否可以达到简化代码的效果:

可以发现现在的代码依然有效,代码简化成功!!
四、丰富构造函数、list增删查改的实现
现在我们已经完成了list的简单构造函数,现在我们就可以参照 c++ library完成其他的构造函数:
4.1 list(size_t n, const T& x = T())
我们要实现的这个函数和标准库中的一样,并且直接复用我峨嵋你已经实现的函数就好了:
list(size_t n, const T& x = T())
{for (int i = 0; i < n; i++){push_back(x);}
}
直接来演示一下的效果:

4.2 拷贝构造
我们就只需要将被拷贝链表的元素一个一个的拷贝进链表就行了:
list(const list<T>& l1)
{empty_init();for (auto& e : l1) push_back(e);
}
我们来测试一下效果:

4.3 插入函数的实现(insert)
想要在这个双向链表中插入节点,我们就需要
-
待插入的值
-
待插入位置
所以,insert函数定义为: void insert(iterator pos, const T& val = T())
iterator insert(iterator pos, const T& val = T())
{node* cur = pos._nd;node* prev = pos._nd->_prev;node* insrt = new node(val);prev->_next = insrt;insrt->_prev = prev;insrt->_next = cur;cur->_prev = insrt;return iterator(cur->_prev);}
这个函数也十分的简单如果,有的uu还没有接触过链表,或者是已经忘了链表的增删查改,可以移步去看看我之前的博客:链表的介绍
4.4链表的删除(earse)
关于erase和函数的定义,我们就只需要拿到需要删除的位置就可以了, 所以定义为:void erase(iterator pos)
iterator erase(iterator pos)
{assert(pos != end()); //! 注意不能够将哨兵位删除!!node* cur = pos._nd;node* prev = cur->_prev;prev->_next = cur->_next;cur->_next->_prev = prev;delete cur;return iterator(prev->_next);}
现在我们就直接来测试一下这个函数是否可以满足我们的要求:

由此可知我们实现的都没有问题。
4.5链表元素的查找(find)
定义find函数时,我们就只需要给函数一个特定的需要查找到的值,然后使这个函数返回这个元素的位置(迭代器)
iterator find(const T& val)
{auto it = begin();while (it != end() && *it != val){it++;}if (*it == val) return it;return nullptr;}

4.6 头删和尾删操作
前面我们已经实现了earse 现在我们就只需要对这个和拿书尽心你给复用就好了:
void pop_front()
{erase(++end());
}
void pop_back()
{erase(--end());
}
接下来我们就直接来演示这个函数是否有用:

五、析构函数与clear函数
最后我们就来实现一下list的析构函数,我们还是继续函数的复用:
// zdl:: 析构类函数的实现:~list(){// ! 不仅要将所有的数值删除还需要将哨兵位也清除!clear();delete _head;_head = nullptr; }void clear(){// !! 不能删除哨兵位,就只是将所有的数值清空。auto it = begin();while (it != end()) it = erase(it);}
现在我们就将已有的链表清空试试:

六、代码展示
list.h
#pragma once #include<iostream>
#include<cassert>
using namespace std;
namespace zdl
{template <class T>struct ListNode{T _data;ListNode<T>* _next;ListNode<T>* _prev;// 节点的构造函数ListNode(const T& val = T()):_data(val),_next(nullptr),_prev(nullptr){}};template<class T, class Ref, class Ptr>struct list_iterator{typedef ListNode<T> node;typedef list_iterator<T, Ref, Ptr> self;node* _nd;list_iterator(node* nd):_nd(nd){}// zdl:: 实现迭代器的基本功能:// 解引用数值Ref operator*(){return _nd->_data;}Ptr operator->(){return &_nd->_data;}// zdl:: 前置++ / --self& operator++(){_nd = _nd->_next;return *this;}self& operator--(){_nd = _nd->_prev;return *this;}self& operator+(size_t n){while (n--){_nd = _nd->_next;}return *this;}self& operator-(size_t n){while (n--){_nd = _nd->_prev;}return *this;}// zdl:: 后置 ++ / --self operator++(int){self tmp = _nd;_nd = _nd->_next;return tmp;}self operator--(int){self tmp = _nd;_nd = _nd->_prev;return tmp;}// zdl:: != 运算bool operator!=(const self& s){return _nd != s._nd;}};template<class T>class list{public:typedef ListNode<T> node;typedef list_iterator<T, T&, T*> iterator;typedef list_iterator<T, const T&, const T*> const_iterator;void empty_init(){// zdl :: 在初始化一个空链表时, 先定义一个哨兵位_head = new node();_head->_next = _head;_head->_prev = _head;}list(){empty_init();}list(const list<T>& l1){empty_init();for (auto& e : l1) push_back(e);}list(size_t n, const T& x = T()){empty_init();for (size_t i = 0; i < n; i++){push_back(x);}}void push_back(const T& val){node* creat = new node(val);node* tail = _head->_prev;tail->_next = creat;creat->_prev = tail;creat->_next = _head;_head->_prev = creat; }void push_front(const T& val){node* fnode = new node(val);fnode->_next = _head->_next;fnode->_prev = _head;_head->_next->_prev = fnode;_head->_next = fnode;}void Print_list(){node* cur = _head->_next;while (cur != _head){cout << cur->_data << " ";cur = cur->_next;}cout << endl;}// zdl:: 增删查改的实现iterator insert(iterator pos, const T& val = T()){node* cur = pos._nd;node* prev = pos._nd->_prev;node* insrt = new node(val);prev->_next = insrt;insrt->_prev = prev;insrt->_next = cur;cur->_prev = insrt;return iterator(cur->_prev);}iterator erase(iterator pos){assert(pos != end()); //! 注意不能够将哨兵位删除!!node* cur = pos._nd;node* prev = cur->_prev;prev->_next = cur->_next;cur->_next->_prev = prev;delete cur;return iterator(prev->_next);}iterator find(const T& val){auto it = begin();while (it != end() && *it != val){it++;}if (*it == val) return it;return nullptr;}void pop_front(){erase(begin());}void pop_back(){erase(--end());}// zdl:: 析构类函数的实现:~list(){// ! 不仅要将所有的数值删除还需要将哨兵位也清除!clear();delete _head;_head = nullptr; }void clear(){// !! 不能删除哨兵位,就只是将所有的数值清空。auto it = begin();while (it != end()) it = erase(it);}
// zdl:: 使用类来模拟迭代器的行为iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}private:node* _head;};
}
test.cpp
#include"list.h"
#include<list>
struct pos
{int row;int col;//构造函数pos(const int& x = 0, const int& y = 0):row(x),col(y){}//成员函数void pos_show(){printf("(%d, %d) ",row, col);}
};
int main()
{// zdl::list<pos> l1;// pos p[] = {{1, 2}, {3, 4}, {5, 6}};// for (int i = 0; i < 3; i++) l1.push_back(p[i]);// auto it = l1.begin();// while (it != l1.end())// {// it->pos_show();// it++;// cout << endl;// }// cout << endl;// zdl::list<int> l2(5, 4);// for (auto&i : l2) cout << i << " ";// cout << endl;// zdl::list<int> l4(3, 3);// l4.Print_list();// l4.insert(l4.begin() + 2, 2);// l4.Print_list();// l4.erase(l4.begin() + 2);// l4.Print_list();// zdl::list<int>l5;// for (int i = 1; i <= 10; i++) l5.push_back(i);// cout << "原数组:" << endl;// l5.Print_list();// // zdl:: 现在我们要借助 find + erase函数来删除元素:5// l5.erase(l5.find(5));// cout << "删除后:" << endl;// l5.Print_list();// zdl:: 进行头删和尾删// cout << "进行尾删和头删后:" << endl;// l5.pop_back();// l5.pop_front();// l5.Print_list();// cout << "现在将所有的元素都删除!" << endl;// l5.clear();// l5.Print_list();zdl::list<int> l1(10, 10);cout <<"l1:" << endl;l1.Print_list();zdl::list<int> l2(l1);cout << "l2:" << endl;l2.Print_list();return 0;
}
好,常用的接口我们就实现了,list学习到此告一段落,再见!!
相关文章:
STL容器-- list的模拟实现(附源码)
STL容器-- list的模拟实现(附源码) List的实现主要考察我们对list这一容器的理解,和代码的编写能力,通过上节对list容器的使用,我们对list容器已经有了一些基本的了解,接下来就让我们来实现一些list容器常见…...
python——句柄
一、概念 句柄指的是操作系统为了标识和访问对象而提供的一个标识符,在操作系统中,每个对象都有一个唯一的句柄,通过句柄可以访问对象的属性和方法。例如文件、进程、窗口等都有句柄。在编程中,可以通过句柄来操作这些对象&#x…...
KubeSphere 与 Pig 微服务平台的整合与优化:全流程容器化部署实践
一、前言 近年来,为了满足越来越复杂的业务需求,我们从传统单体架构系统升级为微服务架构,就是把一个大型应用程序分割成可以独立部署的小型服务,每个服务之间都是松耦合的,通过 RPC 或者是 Rest 协议来进行通信,可以按照业务领域来划分成独立的单元。但是微服务系统相对…...
ESP8266-01S、手机、STM32连接
1、ESP8266-01S的工作原理 1.1、AP和STA ESP8266-01S为WIFI的透传模块,主要模式如下图: 上节说到,我们需要用到AT固件进行局域网应用(ESP8266连接的STM32和手机进行连接)。 ESP8266为一个WiFi透传模块,和…...
Web开发 -前端部分-CSS-2
一 长度单位 代码实现: <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document<…...
【QT用户登录与界面跳转】
【QT用户登录与界面跳转】 1.前言2. 项目设置3.设计登录界面3.1 login.pro参数3.2 界面设置3.2.1 登录界面3.2.2 串口主界面 4. 实现登录逻辑5.串口界面6.测试功能7.总结 1.前言 在Qt应用程序开发中,实现用户登录及界面跳转功能是构建交互式应用的重要步骤之一。下…...
记录一次关于spring映射postgresql的jsonb类型的转化器事故,并使用hutool的JSONArray完成映射
事件的起因是这样的,那次事故发生的起因是因为WebFlux和postgreSQL去重新做鱼皮的鱼图图项目(鱼图图作业)。 在做到picture表的时候,发现postgreSQL中有个jsonb的类型可以更好的支持json数组。 出于锻炼新技术的目的,…...
基于 HTML5 Canvas 制作一个精美的 2048 小游戏--day2
为了使 2048 游戏的设计更加美观和用户友好,我们可以进行以下几项优化: 改善颜色方案:使用更温馨的颜色组合。添加动画效果:为方块的移动和合并添加渐变效果。优化分数显示:在分数增加时使用动画效果。 以下是改进后…...
Django框架:python web开发
1.环境搭建: (a)开发环境:pycharm (b)虚拟环境(可有可无,优点:使用虚拟环境可以把使用的包自动生成一个文件,其他人需要使用时可以直接选择导入包ÿ…...
MySQL、HBase、ES的特点和区别
MySQL:关系型数据库,主要面向OLTP,支持事务,支持二级索引,支持sql,支持主从、Group Replication架构模型(本文全部以Innodb为例,不涉及别的存储引擎)。 HBase࿱…...
联发科MTK6762/MT6762安卓核心板_4G智能模块应用
MT6762安卓核心板是一款工业级高性能、可运行 android9.0 操作系统的 4G智能模块。MT6762平台打造具备 AI 体验、先进双摄像头拍摄效果且具备丰富连接功能的智能手机主板。 MT6762安卓核心板 是一款髙性能低功耗的 4G 全网通安卓智能模块。此模块支持 2G/3G/4G 移动,…...
Windows7系统下载安装Source Code Pro字库
Source Code Pro字库介绍 Source Code Pro是由Adobe推出的一款专为代码展示和编写设计的开源等宽字体。它不仅在编程社区中广受好评,还被广泛应用于各种编辑器环境中,以提升代码的可读性和编程体验。 Source Code Pro的设计充分考虑了编程符号的呈…...
Navicat 17 功能简介 | 商业智能 BI
Navicat 17 功能简介 | 商业智能BI 随着 17 版本的发布,Navicat 也带来了众多的新特性,包括兼容更多数据库、全新的模型设计、可视化智能 BI、智能数据分析、可视化查询解释、高质量数据字典、增强用户体验、扩展 MongoDB 功能、轻松固定查询结果、便捷U…...
C# winodw TableLayoutPanel 料盒生产状态UI自动生成
料盒生产状态UI自动生成,效果如下 以前公司项目的这些都是手动拖控件做的。每个设备的料盒数量不一样,层数不一样时都要发好几个小时去改相关细节和代码。上次改了一次。这个又来了。上次就有想法做成根据参数自动生成。但项目时间有限有没有去深入思路和…...
提示词的艺术----AI Prompt撰写指南(个人用)
提示词的艺术 写在前面 制定提示词就像是和朋友聊天一样,要求我们能够清楚地表达问题。通过这个过程,一方面要不断练习提高自己地表达能力,另一方面还要锻炼自己使用更准确精炼的语言提出问题的能力。 什么样的提示词有用? 有…...
哪些前端打印插件可以实现监听用户选择了打印还是取消
在前端实现监听用户是否选择了打印还是取消的功能,确实是一个挑战,因为浏览器的打印行为是通过原生对话框处理的,而这些对话框的行为无法直接被 JavaScript 控制或监听。不过,有一些插件和方法可以帮助你更接近这个目标࿱…...
【PyCharm】连接Jupyter Notebook
【PyCharm】相关链接 【PyCharm】连接 Git【PyCharm】连接Jupyter Notebook【PyCharm】快捷键使用【PyCharm】远程连接Linux服务器【PyCharm】设置为中文界面 【PyCharm】连接Jupyter Notebook PyCharm连接Jupyter Notebook的过程可以根据不同的需求分为 本地连接 和 远程连…...
【Linux系统编程】—— 深入理解Linux中的环境变量与程序地址空间
文章目录 环境变量常见的环境变量查看环境变量环境变量的修改与使用环境变量的组织⽅式环境变量的命令通过代码如何获取环境变量环境变量的继承 前言:在Linux系统中,环境变量和程序地址空间是系统管理和进程运行的重要组成部分。本文将详细探讨环境变量的…...
Spark常见面试题-部分待更新
1. 简述hadoop 和 spark 的不同点(为什么spark更快) Hadoop是一个分布式管理、存储、计算的生态系统,包括HDFS(分布式文件系统)、MapReduce(计算引擎)和YARN(资源调度器)…...
Android BitmapShader实现狙击瞄具十字交叉线准星,Kotlin
Android BitmapShader实现狙击瞄具十字交叉线准星,Kotlin <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
Xela矩阵三轴触觉传感器的工作原理解析与应用场景
Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知,帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量,能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度,还为机器人、医疗设备和制造业的智…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...
Spring AOP代理对象生成原理
代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】,这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…...
用递归算法解锁「子集」问题 —— LeetCode 78题解析
文章目录 一、题目介绍二、递归思路详解:从决策树开始理解三、解法一:二叉决策树 DFS四、解法二:组合式回溯写法(推荐)五、解法对比 递归算法是编程中一种非常强大且常见的思想,它能够优雅地解决很多复杂的…...
相关类相关的可视化图像总结
目录 一、散点图 二、气泡图 三、相关图 四、热力图 五、二维密度图 六、多模态二维密度图 七、雷达图 八、桑基图 九、总结 一、散点图 特点 通过点的位置展示两个连续变量之间的关系,可直观判断线性相关、非线性相关或无相关关系,点的分布密…...
【QT控件】显示类控件
目录 一、Label 二、LCD Number 三、ProgressBar 四、Calendar Widget QT专栏:QT_uyeonashi的博客-CSDN博客 一、Label QLabel 可以用来显示文本和图片. 核心属性如下 代码示例: 显示不同格式的文本 1) 在界面上创建三个 QLabel 尺寸放大一些. objectName 分别…...
