用庫造一個list的輪子 【C++】

文章目錄

  • list的模擬實現
    • 默認成員函數
      • 構造函數
      • 拷貝構造函數
      • 賦值運算符重載
      • 析構函數
    • 迭代器
      • 迭代器為什么要存在?
      • const_iterator
      • begin和end
    • insert
    • erase
    • push_back && pop_back
    • push_front &&pop_front
    • swap
  • 完整代碼

list的模擬實現

默認成員函數

構造函數

list是一個帶頭雙向循環鏈表,在構造一個list對象時,new一個頭結點,并讓其prev和next都指向自己即可。

  	void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}//默認構造list(){empty_init();}

拷貝構造函數

//拷貝構造函數
list(const list<T>& lt)
{_head = new node; //申請一個頭結點_head->_next = _head; //頭結點的后繼指針指向自己_head->_prev = _head; //頭結點的前驅指針指向自己for (auto & e : lt) //兩個 e都是同一個{push_back(e); //將容器lt當中的數據一個個尾插到新構造的容器后面}
}

賦值運算符重載

版本一(推薦):
參數不使用引用,讓編譯器自動調用list的拷貝構造函數構造出來一個list對象,然后調用swap函數將原容器與該list對象進行交換

這樣做相當于將應該用clear清理的數據,通過交換函數交給了容器lt,而當賦值運算符重載函數調用結束時,容器lt會自動銷毀,并調用其析構函數進行清理。

list<T> & operator= (list<T>  lt)//右值沒有引用傳參,間接調用拷貝構造//list<T>& operator= (  list<T> * this, list<T>  lt)//右值沒有引用傳參,間接調用拷貝構造// lt1 = lt2{this->swap(lt);return *this; }

版本二:
先調用clear函數將原容器清空,然后將容器lt當中的數據,通過遍歷的方式一個個尾插到清空后的容器當中即可。

  
list<T>& operator=(const list<T>& lt)
{if (this != &lt) //避免自己給自己賦值{clear(); //清空容器for (const auto& e : lt){push_back(e); //將容器lt當中的數據一個個尾插到鏈表后面}}return *this; //支持連續賦值
}

析構函數

對對象進行析構時,首先調用clear函數清理容器當中的數據,然后將頭結點釋放,最后將頭指針置空

	 	void clear(){iterator it = begin();while (it!= end() )	{it = erase(it);}_size = 0;}~list(){clear();delete _head;_head = nullptr;}

迭代器

迭代器為什么要存在?

string 和vector的迭代器

string和vector將數據存儲在一段連續的內存空間,那么可以通過指針進行自增、自減以及解引用等操作,就可以對相應位置的數據進行一系列操作,所以string和vector是天然的迭代器

在這里插入圖片描述
list的迭代器
list中各個結點在內存當中的位置是隨機的,不一定是連續的,我們不能僅通過結點指針的自增、自減以及解引用等操作對相應結點的數據進行操作 ,采用類封裝迭代器,在迭代器類的內部,重載 ++ 、 --、 *、 -> 、 !=、 == 這些迭代器會用到的運算符

在這里插入圖片描述

const_iterator

在const迭代器中,const迭代器指向的內容不能被修改。也就是解引用返回的值不能被修改。迭代器本身是可以修改的,有兩種解決方案 :
1 再封裝一個const迭代器類

	template< class T>//const 迭代器 ,讓迭代器指向的內容不能修改, 迭代器本身可以修改struct __list_const_iterator{typedef list_node<T>  Node;//構造函數__list_const_iterator(Node* node):_node(node){}const T& operator*()//出了作用域,節點的值還在,用引用//const: 返回節點的值,不能修改{return _node->_val;}//前置++,返回++之后的值__list_const_iterator& operator++()//__list_const_iterator& operator++(__list_const_iterator  * this  ){_node = _node->_next;return *this;}//后置++ ,返回++之前的值__list_const_iterator operator++(int){__list_const_iterator tmp(*this);_node = _node->_next;return tmp;// tmp出了作用域就被銷毀 ,用傳值返回 }bool operator==(const __list_iterator<T>& it){return *this == it._node;}bool operator!=(const __list_iterator<T>& it)//傳值返回,返回的是拷貝,是一個臨時對象,臨時對象具有常性{return *this != it._node;}Node* _node;};

2 選擇增加模板參數,復用代碼(推薦)

template<class T, class Ref, class Ptr>

在這里插入圖片描述

c++庫就是用的這種解決方案

	//template<class T> //list類存儲的數據是任意類型,所以需要設置模板參數//普通迭代器//Ref是引用 ,Ptr是指針template<class T,class Ref,class Ptr>struct  __list_iterator{typedef list_node<T> Node;typedef __list_iterator<T, Ref, Ptr>  self;//構造函數__list_iterator(Node* node):_node(node){}Ref operator*(){return _node->_val;}Ptr operator->(){return &_node->_val;}//前置++,返回++之后的值self & operator++()//__list_iterator<T> & operator++(__list_iterator<T> * this  ){_node = _node->_next;return *this;}//后置++ ,返回++之前的值self  operator++(int)//	__list_iterator<T> operator++( __list_iterator<T> * this ,int){self tmp(*this);//拷貝構造_node = _node->_next;return tmp; // tmp出了作用域就被銷毀 ,用傳值返回 }bool operator!= (const self& it){return _node != it._node;}bool operator== (const self & it){return _node == it._node;}Node* _node;};template<class T>//list類存儲的數據是任意類型,所以需要設置模板參數class list{typedef list_node<T>  Node;public:typedef  __list_iterator<T ,T&,T* >  iterator;typedef  __list_iterator<T, const T&, const T * >  const_iterator;//迭代器 //能直接顯示構造最好顯式構造,不要把決定權給編譯器進行單參數的隱式類型轉換iterator end()  //最后一個數據的下一個位置,即頭節點{//return _head; // _head的類型是list_node<T>* ,iterator的類型是__list_iterator<T> ,類型不一致,涉及到單參數的構造函數支持隱式類型轉換 //還可以寫成 return iterator(_head);return iterator(_head);}iterator begin()//第一個數據的位置,即頭節點的下一個位置{//return _head->_next;//單參數的構造函數支持隱式類型轉換//還可以寫成 return iterator(_head->_next)return iterator(_head->_next);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}//默認構造list(){empty_init();}// lt2(lt1)//還沒有實現const_iteratorlist(const list<T>& lt){empty_init();//拷貝數據for (auto & e :lt )//遍歷lt{push_back(e);}}~list(){clear();delete _head;_head = nullptr;}void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}void swap(list<T> & lt){std:: swap(_head,lt._head );std::swap(_size, lt._size);}list<T> & operator= (list<T>  lt)//右值沒有引用傳參,間接調用拷貝構造//list<T>& operator= (  list<T> * this, list<T>  lt)//右值沒有引用傳參,間接調用拷貝構造// lt1 = lt2{this->swap(lt);return *this; }void clear(){iterator it = begin();while (it!= end() )	{it = erase(it);}_size = 0;}void push_back(const T& x){insert(end(), x);//在最后一個數據的下一個位置插入}//pos位置之前插入iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);// prev newnode cur 鏈接關系prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;++_size;return newnode;}iterator erase (iterator pos){assert(pos != end());Node* cur = pos._node;Node* next = cur->_next;Node* prev = cur->_prev;//prev next prev->_next = next;next->_prev = prev;delete cur;--_size;return next;}size_t size(){return _size;}void push_front( const T & x )//T可能是vector ,用引用,減少拷貝{insert(begin(),x);}void pop_back(){erase(--end());//end是最后一個數據的下一個位置,需要--,到達最后一個數據,這樣才是尾刪}void pop_front(){erase(begin());}private:Node* _head;size_t _size;};

當我們定義const對象時,會自動調用const修飾的迭代器。當調用const修飾的迭代器時,__list_iterator的模板參數就會實例化為const T&。實際上在實例化時,const和非const修飾的還是兩個不同類,只不過是實例化的代碼工作交給了編譯器處理了。

begin和end

對于list,第一個有效數據的迭代器就是頭結點后一個結點
begin函數返回的是第一個有效數據的迭代器,即頭節點的下一個位置
end函數返回的是最后一個有效數據的下一個位置的迭代器,即頭節點

		iterator end()  //最后一個數據的下一個位置,即頭節點{return _head; // _head的類型是list_node<T>* ,iterator的類型是__list_iterator<T> ,類型不一致,涉及到單參數的構造函數支持隱式類型轉換 //還可以寫成 return iterator(_head);}iterator begin()//第一個數據的位置,即頭節點的下一個位置{return _head->_next;//單參數的構造函數支持隱式類型轉換//還可以寫成 return iterator(_head->_next)}

const對象的begin函數和end函數

	const_iterator begin() const{return const_iterator(_head->_next);//返回使用頭結點后一個結點}const_iterator end() const{return const_iterator(_head);//返回使用頭結點}

insert

在這里插入圖片描述

重新改變prev newnode cur 三者之間的鏈接關系

 	//pos位置之前插入iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);// prev newnode cur 鏈接關系prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;++_size;return newnode;}

erase

在這里插入圖片描述
改變prev和next之間的鏈接關系,然后釋放cur

iterator erase (iterator pos){assert(pos != end());Node* cur = pos._node;Node* next = cur->_next;Node* prev = cur->_prev;//prev next prev->_next = next;next->_prev = prev;delete cur ;--_size;return next;}

push_back && pop_back

	void push_back(const T& x){insert(end(), x);//在最后一個數據的下一個位置插入}void pop_back(){erase(--end());//end是最后一個數據的下一個位置,需要--,到達最后一個數據,這樣才是尾刪}

push_front &&pop_front

		void pop_front(){erase(begin());}void push_front( const T & x )//T可能是vector ,用引用,減少拷貝{insert(begin(),x);}

swap

swap函數用于交換兩個容器,list容器當中存儲的是鏈表的頭指針和size,我們將這兩個容器當中的頭指針和size交換

		void swap(list<T> & lt){std:: swap(_head,lt._head );std::swap(_size, lt._size);}

注意: 這里調用庫里的swap模板函數,需要在swap函數之前加上“std::”,告訴編譯器在c++標準庫尋找swap函數,否則編譯器編譯時會認為你調用的是正在實現的swap函數(就近原則)

總結

在這里插入圖片描述

完整代碼

#pragma once
#include<iostream>
#include<assert.h>
#include<list>
using namespace std;
namespace cxq
{//list類存儲的數據是任意類型,所以需要設置模板參數template<class T>//節點struct list_node{//構造函數list_node(const T& val = T()) //缺省值是匿名對象,c++對內置類型進行了升級:_prev(nullptr), _next(nullptr), _val(val){}list_node<T>* _prev;list_node<T>* _next;T _val;};//template<class T> //list類存儲的數據是任意類型,所以需要設置模板參數//普通迭代器//Ref是引用 ,Ptr是指針template<class T,class Ref,class Ptr>struct  __list_iterator{typedef list_node<T> Node;typedef __list_iterator<T, Ref, Ptr>  self;//構造函數__list_iterator(Node* node):_node(node){}Ref operator*(){return _node->_val;}Ptr operator->(){return &_node->_val;}//前置++,返回++之后的值self & operator++()//__list_iterator<T> & operator++(__list_iterator<T> * this  ){_node = _node->_next;return *this;}//后置++ ,返回++之前的值self  operator++(int)//	__list_iterator<T> operator++( __list_iterator<T> * this ,int){self tmp(*this);//拷貝構造_node = _node->_next;return tmp; // tmp出了作用域就被銷毀 ,用傳值返回 }bool operator!= (const self& it){return _node != it._node;}bool operator== (const self & it){return _node == it._node;}Node* _node;};//template< class T>const 迭代器 ,讓迭代器指向的內容不能修改, 迭代器本身可以修改//struct __list_const_iterator//{//	typedef list_node<T>  Node;//	//構造函數//	__list_const_iterator(Node* node)//		:_node(node)//	{//	}//	const T& operator*()//出了作用域,節點的值還在,用引用//		//const: 返回節點的值,不能修改//	{//		return _node->_val;//	}//	//前置++,返回++之后的值//	__list_const_iterator& operator++()//		//__list_const_iterator& operator++(__list_const_iterator  * this  )//	{//		_node = _node->_next;//		return *this;//	}//	//后置++ ,返回++之前的值//	__list_const_iterator operator++(int)//	{//		__list_const_iterator tmp(*this);//		_node = _node->_next;//		return tmp;// tmp出了作用域就被銷毀 ,用傳值返回 //	}//	bool operator==(const __list_iterator<T>& it)//	{//		return *this == it._node;//	}//	bool operator!=(const __list_iterator<T>& it)//傳值返回,返回的是拷貝,是一個臨時對象,臨時對象具有常性//	{//		return *this != it._node;//	}//	Node* _node;//};template<class T>//list類存儲的數據是任意類型,所以需要設置模板參數class list{typedef list_node<T>  Node;public:typedef  __list_iterator<T ,T&,T* >  iterator;//普通迭代器typedef  __list_iterator<T, const T&, const T * >  const_iterator;//const 迭代器//迭代器 //能直接顯示構造最好顯式構造,不要把決定權給編譯器進行單參數的隱式類型轉換iterator end()  //最后一個數據的下一個位置,即頭節點{//return _head; // _head的類型是list_node<T>* ,iterator的類型是__list_iterator<T> ,類型不一致,涉及到單參數的構造函數支持隱式類型轉換 //還可以寫成 return iterator(_head);return iterator(_head);}iterator begin()//第一個數據的位置,即頭節點的下一個位置{//return _head->_next;//單參數的構造函數支持隱式類型轉換//還可以寫成 return iterator(_head->_next)return iterator(_head->_next);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}//默認構造list(){empty_init();}// lt2(lt1)//還沒有實現const_iteratorlist(const list<T>& lt){empty_init();//拷貝數據for (auto & e :lt )//遍歷lt{push_back(e);}}~list(){clear();delete _head;_head = nullptr;}void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}void swap(list<T> & lt){std:: swap(_head,lt._head );std::swap(_size, lt._size);}list<T> & operator= (list<T>  lt)//右值沒有引用傳參,間接調用拷貝構造//list<T>& operator= (  list<T> * this, list<T>  lt)//右值沒有引用傳參,間接調用拷貝構造// lt1 = lt2{this->swap(lt);return *this; }void clear(){iterator it = begin();while (it!= end() )	{it = erase(it);}_size = 0;}void push_back(const T& x){找尾//Node* tail = _head->_prev;//Node* newnode = new Node(x);改變鏈接關系 ///*newnode = tail->next;*///tail->_next = newnode;//newnode->_prev = tail;//_head->_prev = newnode;//newnode->_next = _head;insert(end(), x);//在最后一個數據的下一個位置插入}//pos位置之前插入iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);// prev newnode cur 鏈接關系prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;++_size;return newnode;}iterator erase (iterator pos){assert(pos != end());Node* cur = pos._node;Node* next = cur->_next;Node* prev = cur->_prev;//prev next prev->_next = next;next->_prev = prev;delete cur;--_size;return next;}size_t size(){return _size;}void push_front( const T & x )//T可能是vector ,用引用,減少拷貝{insert(begin(),x);}void pop_back(){erase(--end());//end是最后一個數據的下一個位置,需要--,到達最后一個數據,這樣才是尾刪}void pop_front(){erase(begin());}private:Node* _head;size_t _size;};void test_list1(){list<int> lt1;lt1.push_back(1);lt1.push_back(2);list<int>::iterator it = lt1.begin();//拷貝構造while (it != lt1.end()){cout << *it << " ";it++;}cout << endl;}void test_list2(){list<int> lt1;lt1.push_back(1);lt1.push_back(2);list<int> lt2 (lt1);for (auto e : lt1){cout << e << " ";}cout << endl;}
}

如果你覺得這篇文章對你有幫助,不妨動動手指給點贊收藏加轉發,給鄃鱈一個大大的關注你們的每一次支持都將轉化為我前進的動力!!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/35550.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/35550.shtml
英文地址,請注明出處:http://en.pswp.cn/news/35550.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HCIP BGP小綜合

BGP小綜合 AS配置AS1AS2 中的小自治系統64512AS2 中的小自治系統64513AS3 測試 首先該實驗分成三個AS&#xff0c;AS2里面有聯邦&#xff0c;所以配置順序 要先將IBGP通&#xff0c;然后配置AS1,AS3和聯邦 AS配置 AS1 R1 # bgp 1router-id 1.1.1.1peer 12.1.1.2 as-number …

二十二、責任鏈模式

目錄 1、使用demo演示責任鏈模式2、傳統方案解決oa系統審批3、傳統方案解決oa系統審批存在的問題4、職責鏈模式基本介紹5、職責鏈模式原理類圖6、職責鏈模式解決oa系統采購審批7、職責鏈模式的注意事項和細節8、職責鏈模式的實際使用場景舉例 1、使用demo演示責任鏈模式 學校o…

數據庫相關面試題

鞏固基礎&#xff0c;砥礪前行 。 只有不斷重復&#xff0c;才能做到超越自己。 能堅持把簡單的事情做到極致&#xff0c;也是不容易的。 mysql怎么優化 : MySQL的優化可以從以下幾個方面入手&#xff1a; 數據庫設計優化&#xff1a;合理設計表結構&#xff0c;選擇合適的數…

GitHub 如何部署寫好的H5靜態頁面

感謝粉皮zu的私信&#xff0c;又有素材寫筆記了。(●’?’●) 剛好記錄一下我示例代碼的GitHub部署配置&#xff0c;以便于后期追加倉庫。 效果 環境 gitwin 步驟 第一步 新建倉庫 第二步 拉取代碼 將倉庫clone到本地 git clone 地址第三步 部署文件 新建.github\workflo…

vue-pc端elementui-統一修改問題-Dialog 對話框點擊空白關閉問題-element-所有組件層級問題

前言 實際開發我們經常發現dialog彈出框默認點擊遮罩層空白地方就會關閉-有屬性可以關閉 但是經常會圖方便-或者已經寫完了&#xff0c;不想一個個寫&#xff0c;可以在main.js進行統一關閉 當我們在頁面進行復雜設計和層級關閉改變&#xff0c;會發現右上角的退出登錄彈出款…

現代無人機技術

目錄 1.發展 2.應用領域 3.對戰爭的影響 4.給人類帶來的福利 5.給人類帶來的壞處 1.發展 無人機的發展可以分為以下幾個關鍵步驟&#xff1a; 1. 早期試驗和研究&#xff1a;20世紀初&#xff0c;飛行器的概念開始出現&#xff0c;并進行了一些早期的試飛和實驗。這些嘗試包…

LeetCode150道面試經典題-- 有效的字母異位詞(簡單)

1.題目 給定兩個字符串 s 和 t &#xff0c;編寫一個函數來判斷 t 是否是 s 的字母異位詞。 注意&#xff1a;若 s 和 t 中每個字符出現的次數都相同&#xff0c;則稱 s 和 t 互為字母異位詞。 2.示例 s"adasd" t"daads" 返回true s"addad" t &q…

常見設計模式

概念 設計模式是怎么解決問題的一種方案 常見的設計模式 單例模式 概念&#xff1a;保證一個類僅有一個實例&#xff0c;并提供一個訪問它的全局訪問點。 應用&#xff1a;項目封裝個websocket用于大屏&#xff0c;redux&#xff0c;vuex都應用了單例模式的思想&#xff1b…

文獻閱讀:AnnoLLM: Making Large Language Models to Be Better Crowdsourced Annotators

文獻閱讀&#xff1a;AnnoLLM: Making Large Language Models to Be Better Crowdsourced Annotators 1. 文章簡介2. 方法介紹3. 實驗考察 1. 實驗結果2. 消解實驗3. Consistency & Stability 4. 結論 & 思考 文獻鏈接&#xff1a;https://arxiv.org/abs/2303.16854 …

Golang設計模式

Golang設計模式 Golang設計模式簡介Golang工廠設計模式Golang單例設計模式Golang抽象工廠設計模式Golang建造者模式 (Builder Pattern)Golang 原型模式(Prototype Pattern)Golang適配器模式Golang 橋接模式&#xff08;Bridge Pattern&#xff09;Golang裝飾器模式(Decorator …

j東h5st參數多局部ob加密(js_security_v3_0.1.4.js)加密分析

j東h5st參數多局部多次ob加密&#xff08;js_security_v3_0.1.4.js&#xff09; 大家好呀&#xff0c;我是你們的好兄弟&#xff0c;【星云horseAK】&#xff0c;今天的主題真的是千呼萬喚始出來&#xff0c;某東東的h5st參數&#xff0c;這個加密的js文件使用了obfuscator進行…

《Java-SE-第三十六章》之枚舉

前言 在你立足處深挖下去,就會有泉水涌出!別管蒙昧者們叫嚷:“下邊永遠是地獄!” 博客主頁&#xff1a;KC老衲愛尼姑的博客主頁 博主的github&#xff0c;平常所寫代碼皆在于此 共勉&#xff1a;talk is cheap, show me the code 作者是爪哇島的新手&#xff0c;水平很有限&…

Linux 日志管理

Linux 日志管理 一.Linux 下的日志服務簡介 1.1 CentOS5 之前的版本 centos5 之前的版本使用系統和內核日志分離的格式記錄日志 syslogd:該服務專門用于記錄系統日志(system application logs) klogd: 該服務專門用于記錄內核日志(linux kernel logs) centos5 之前事件的記錄格…

Redis_Geospatial(基于位置信息的應用)

12.Geospatial 12.1 簡介 基于位置信息服務(Location-Based Service,LBS)的應用。Redis3.2版本后增加了對GEO類型的支持。主要來維護元素的經緯度。redis基于這種類型&#xff0c;提供了經緯度設置、查詢、范圍查詢、距離查詢、經緯度hash等一些相關操作 12.2 GEO底層結構 …

war和war exploded

war和war exploded的區別 war模式&#xff1a;將WEB工程以包的形式上傳到服務器 &#xff1b; war exploded模式&#xff1a;將WEB工程以當前文件夾的位置關系上傳到服務器&#xff1b;>> war包是自己打包生成的&#xff0c;如pom文件中<packaging>war</packag…

使用 Visual Studio Code 調試 CMake 腳本

之前被引入到 Visual Studio 中的 CMake 調試器&#xff0c;現已在 Visual Studio Code 中可用。 也就是說&#xff0c;現在你可以通過在 VS Code 中安裝 CMake 工具擴展&#xff0c;來調試你的 CMakeLists.txt 腳本了。是不是很棒? 背景知識 Visual C 開發團隊和 CMake 的維…

Flutter源碼分析筆記:Widget類源碼分析

Flutter源碼分析筆記 Widget類源碼分析 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at: https://jclee95.blog.csdn.netEmail: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550263/article/details/132259681 【介紹】&#x…

TestNG和Junit5測試框架梳理

一、testNG 1. testNG優勢 注解驅動&#xff1a; TestNG 使用注解來標識測試方法、測試類和配置方法&#xff0c;使得測試更具可讀性。 并行執行&#xff1a; TestNG 支持多線程并行執行測試&#xff0c;可以加速測試套件的執行。 豐富的配置&#xff1a; 可以通過 XML 配置文…

Qt下載安裝及配置教程

進入qt中文網站&#xff1a;https://www.qt.io/zh-cn/ 下載開源版 往下滑&#xff0c;下載Qt在線安裝程序 它已經檢測出我的是windows系統&#xff0c;直接點擊download就好。如果是其它的系統&#xff0c;需要找到對應自己系統的安裝包。 然后跟網速有關&#xff0c;等…