《吃透 C++ 類和對象(中):拷貝構造函數與賦值運算符重載深度解析》

🔥個人主頁:@草莓熊Lotso

🎬作者簡介:C++研發方向學習者

📖個人專欄:?《C語言》?《數據結構與算法》《C語言刷題集》《Leetcode刷題指南》

??人生格言:生活是默默的堅持,毅力是永久的享受。

前言: 在上篇博客中我們學習了構造函數和析構函數這兩個類中的默認成員函數,今天這篇博客我想繼續為大家分享拷貝構造函數和賦值運算符重載。主要是先介紹特點再通過舉例說明,所以舉例中的代碼注釋是很重要的。


目錄

一.拷貝構造函數

拷貝構造的特點:

舉例說明:(注意看注釋)?

二.賦值運算符重載

運算符重載:

舉例說明:(注意注釋)

賦值運算符重載:

賦值運算符重載的特點:

舉例說明:(注意注釋)?


一.拷貝構造函數

如果一個構造函數的第?個參數是自身類類型的引用,且任何額外的參數都有默認值,則此構造函數也叫做拷貝構造函數,也就是說拷貝構造是?個特殊的構造函數。

拷貝構造的特點:

  1. 拷貝構造函數是構造函數的?個重載。
  2. 拷貝構造函數的第?個參數必須是類類型對象的引用,使用傳值方式編譯器直接報錯,因為語法邏輯上會引發無窮遞歸用。 拷貝構造函數也可以多個參數,但是第一個參數必須是類類型對象引用,后面的參數必須有缺省值。
  3. C++規定自定義類型對象進行拷貝行為必須調用拷貝構造,所以這里自定義類型傳值傳參和傳值返回都會調用拷貝構造完成
  4. 若未顯式定義拷貝構造,編譯器會自動生成拷貝構造函數。自動生成的拷貝構造對內置類型成員變量會完成值拷貝/淺拷貝(?個字節?個字節的拷貝)(這里和構造與析構不一樣,它是會對內置類型有特定處理的),對自定義類型成員變量會調用他的拷貝構造。
  5. 像Date這樣的類成員變量全是內置類型且沒有指向什么資源,編譯器自動生成的拷貝構造就可以完成需要的拷貝,所以不需要我們顯示實現拷貝構造。像Stack這樣的類,雖然也都是內置類型,但是_a指向了資源,編譯器自動生成的拷貝構造完成的值拷貝/淺拷貝不符合我們的需求,所以需要我們自己實現深拷貝(對指向的資源也進行拷貝)。像MyQueue這樣的類型內部主要是自定義類型Stack成員,編譯器自動生成的拷貝構造會調用Stack的拷貝構造,也不需要我們顯示實現MyQueue的拷貝構造。這里還有一個小技巧,如果?個類顯示實現了析構并釋放資源(也可以說必須顯示實現析構),那么他就需要顯示寫拷貝構造,否則就不需要。
  6. 傳值返回會產生?個臨時對象調用拷貝構造,傳值引用返回,返回的是返回對象的別名(引用),沒有產生拷貝。但是如果返回對象是?個當前函數局部域的局部對象,函數結束就銷毀了,那么使用引用返回是有問題的,這時的引用相當于?個野引用,類似?個野指針?樣。傳引用返回可以減少拷貝,但是?定要確保返回對象,在當前函數結束后還在,才能用引用返回。

--上述特點在舉例說明中都會體現出來?

關于無窮遞歸圖示:

舉例說明:(注意看注釋)?

#include<iostream>
using namespace std;class Date 
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//拷貝構造函數//Date(Date d),這種寫法不行,我們可以拿個func的例子看看,會發現傳值要先調用拷貝函數,下面有提到// 但是拷貝函數本身再一直調用拷貝函數本身的話,會出現無限遞歸的問題,所以要使用傳引用傳參//加個const可以讓下面傳實參的選擇更多,避免出現權限擴大等問題Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}//其實這里用默認生成的也會處理內置類型,進行淺拷貝,在這里是沒問題的。這也是和構造和析構的一個區別//用指針實現拷貝,但是這里并不算拷貝函數/*Date(Date* d){_year = d->_year;_month = d->_month;_day = d->_day;}*/void Print(){cout << _year << "/" << _month << "/" << _day << '\n';}
private:int _year;int _month;int _day;
};//自定義類型傳值傳參和傳值返回都會調用拷貝構造完成
//傳值傳參會調用拷貝函數
void func(Date d)
{}//傳值返回也會調用拷貝函數,但是傳引用就不會(后續會用Stack繼續來講),這里就不過多介紹了
//Date& func2()
Date func2()//這里最好用傳值返回
{Date d(2025,7,31);return d;
}int main()
{Date d1(2025,8,1); Date d2(d1);//func(d1);//我們調試發現,他會先去調用Date里面的拷貝函數再去func//傳值返回可以,傳引用返回不行,這里不細講Date ret = func2();//Date ret = (func2());,這樣寫也是可以的//由這個我們還可以看出,那其實之前的拷貝也可以寫出這樣//Date d2 = d1;// 這里可以完成拷?,但是不是拷?構造,只是?個普通的構造//Date d2(&d1);d1.Print();d2.Print();return 0;
}

關于對內置類型處理和深淺拷貝的相關示例: (注意注釋,用的棧)

#include<iostream>
using namespace std;
typedef int STDataType;class Stack 
{
public:Stack(int n=4){_a = (int*)malloc(n * sizeof(int));if (_a == nullptr){perror("malloc fail!");exit(1);}_top = 0;_capacity = n;}//這樣寫是錯的,因為這里的數組如果像這樣寫僅僅是淺拷貝,后續析構函數釋放空間會釋放同一塊空間// 畫圖理解,調試也會報錯/*Stack(const Stack& s){_a = s._a;_capacity = s._capacity;_top = s._top;}*///所以我們需要這樣寫Stack(const Stack& s){_a = (STDataType*)malloc(sizeof(STDataType) * s._capacity);//申請一塊同樣大小的空間if (_a == nullptr){perror("malloc fail!");exit(1);}//把值再拷貝過去memcpy(_a, s._a, s._top * sizeof(STDataType));//這兩個直接這樣就可以了_capacity = s._capacity;_top = s._top;}//補充一點,這里也不能不寫,用編譯器自動生成的默認的拷貝構造函數,因為這個函數雖然會處理內置類型//但是只會是淺拷貝/值拷貝,像Stack這樣需要有深拷貝的就不行了//可以這樣說,如果一個類必須顯示實現析構函數(需要釋放資源),那么他就一定也要顯示寫拷貝構造函數void Push(STDataType x){if (_top == _capacity){int newcapacity = _capacity * 2;STDataType* tmp = (STDataType*)realloc(_a, newcapacity *sizeof(STDataType));if (tmp == NULL){perror("realloc fail");exit(1);}_a = tmp;_capacity = newcapacity;}_a[_top++] = x;}~Stack(){cout<<"~Stack()"<<'\n';if (_a){free(_a);_a = nullptr;}_top = 0;_capacity = 0;}
private://內置類型STDataType* _a;int _top;int _capacity;
};int main()
{Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2(s1);return 0;
}

圖示如下:

理解技巧:可以這樣說,如果一個類必須顯示實現析構函數(需要釋放資源),那么他就一定也要顯示寫拷貝構造函數

借助上面的棧的類(這里就不再寫出來了),給大家對比看看傳引用返回在這里的弊端,同時也是在說第6個特點 :(注意注釋)

int& func1()
{int x = 1;return x;
}//自定義類型傳值返回是會調用拷貝函數的,但是傳引用返回不會,畫圖分析。
//它沒調拷貝函數的話,在后面函數棧幀銷毀,st析構掉了之后。你再通過別名來找,就出問題了,畫圖
//Stack func2()
Stack& func2()
{Stack st;return st;
}int main()
{int ret1 = func1();cout << ret1 << '\n';//可能是1也可能是隨機值,我們之前判斷過//但是這個棧就很明顯了,我們調試看看Stack ret2 = func2();//這里其實也是拷貝return 0;
}

?--會報realloc fail,但是上面的結構需要改一下(int改size_t),不然不會報這個錯誤

??再來看看如果是默認生成的拷貝構造函數對自定義類型的處理:(注意注釋)

#include<iostream>
using namespace std;
typedef int STDataType;class Stack
{
public:Stack(int n = 4){_a = (int*)malloc(n * sizeof(int));if (_a == nullptr){perror("malloc fail!");exit(1);}_top = 0;_capacity = n;}Stack(const Stack& s){_a = (STDataType*)malloc(sizeof(STDataType) * s._capacity);//申請一塊同樣大小的空間if (_a == nullptr){perror("malloc fail!");exit(1);}//把值再拷貝過去memcpy(_a, s._a, s._top * sizeof(STDataType));//這兩個直接這樣就可以了_capacity = s._capacity;_top = s._top;}//補充一點,這里也不能不寫,用編譯器自動生成的默認的拷貝構造函數,因為這個函數雖然會處理內置類型//但是只會是淺拷貝/值拷貝,像Stack這樣需要有深拷貝的就不行了//可以這樣說,如果一個類必須顯示實現析構函數(需要釋放資源),那么他就一點也要顯示寫拷貝構造函數void Push(STDataType x){if (_top == _capacity){int newcapacity = _capacity * 2;STDataType* tmp = (STDataType*)realloc(_a, newcapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc fail");exit(1);}_a = tmp;_capacity = newcapacity;}_a[_top++] = x;}~Stack(){cout << "~Stack()" << '\n';if (_a){free(_a);_a = nullptr;}_top = 0;_capacity = 0;}
private://內置類型STDataType* _a;int _top;int _capacity;
};class MyQueue
{
public://編譯器默認生成MyQueue的構造函數調用了Stack的構造函數,完成了兩個成員的初始化//編譯器默認生成MyQueue的拷貝構造函數調用了Stack的拷貝構造函數,完成了拷貝//編譯器默認生成MyQueue的析構函數調用了Stack的析構函數,釋放的Stack內部的資源
private://自定義類型Stack _pushst;Stack _popst;//內置類型,但很奇怪,混在這里它卻能處理,這里大家可以自己去試試//int size = 0;
};
int main()
{Stack st1;st1.Push(1);st1.Push(2);// Stack如果不顯示實現拷?構造,用自動生成的拷?構造完成淺拷?// 會導致st1和st2里面的_a指針指向同?塊資源,析構時會析構兩次,程序崩潰Stack st2 = st1;MyQueue mq1;// MyQueue自動生成的拷?構造,會自動調用Stack拷?構造完成pushst/popst的拷?。// 只要Stack拷?構造自己實現了深拷?,這里就沒問題MyQueue mq2 = mq1;return 0;
}


二.賦值運算符重載

--在正式學習賦值運算符重載之前我們需要先了解一下運算符重載

運算符重載:

  • 當運算符被用于類類型的對象時,C++語言允許我們通過運算符重載的形式指定新的含義。C++規定類類型對象使用運算符時,必須轉換成調用對應運算符重載,若沒有對應的運算符重載,則會編譯報錯。
  • 運算符重載是具有特殊名字的函數,他的名字是由operator和后面要定義的運算符共同構成。和其他函數?樣,它也具有其返回類型和參數列表以及函數體。
  • 重載運算符函數的參數個數和該運算符作用的運算對象數量?樣多。一元運算符有?個參數,二元運算符有兩個參數,?元運算符的左側運算對象傳給第?個參數,右側運算對象傳給第二個參數。
  • 如果一個重載運算符函數是成員函數,則它的第?個運算對象默認傳給隱式的this指針,因此運算符重載作為成員函數時,參數比運算對象少一個。
  • 運算符重載以后,其優先級和結合性與對應的內置類型運算符保持?致。
  • 不能通過連接語法中沒有的符號來創建新的操作符:比如operator@。
  • .* (點*),:: ,sizeof ,?:? ,. (點)注意以上5個運算符不能重載。(選擇題里面常考,大家要記一下)
  • 重載操作符至少有一個類類型參數,不能通過運算符重載改變內置類型對象的含義,如: int?operator+(int x, int y)
  • 一個類需要重載哪些運算符,是看哪些運算符重載后有意義,比如Date類重載operator-就有意義,但是重載operator+(當日期加日期時)就沒有意義(加天數還是可以的)。
  • 重載++運算符時,有前置++和后置++,運算符重載函數名都是operator++,無法很好的區分。C++規定,后置++重載時,增加?個int形參,跟前置++構成函數重載,方便區分。
  • 重載<<和>>時,需要重載為全局函數,因為重載為成員函數,this指針默認搶占了第?個形參位置,第?個形參位置是左側運算對象,調?時就變成了 對象<<cout,不符合使用習慣和可讀性。重載為全局函數把ostream/istream放到第?個形參位置就可以了,第?個形參位置當類類型對象。

--上述特點在舉例說明中大多都會提到,其中最后三個特點會在后續的博客中講解?

舉例說明:(注意注釋)

#include<iostream>
using namespace std;class Date 
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}//其實這里用默認生成的也會處理內置類型,進行淺拷貝,在這里是沒問題的。//這也是和構造和析構的一個區別,構造和析構不會處理內置類型int Getyear(){return _year;}//d1==d2,傳d2就行,d1有this指針,但是在實參和形參不能直接寫出來,函數體內可以bool operator==(const Date& d2){return this->_year == d2._year&& this->_month == d2._month&& this->_day == d2._day;}void Print(){cout << _year << "/" << _month << "/" << _day << '\n';}
private:int _year;int _month;int _day;
};// 重載為全局的面臨對象訪問私有成員變量的問題
// 有幾種方法可以解決:
// 1、成員放公有--這個最容易,但是不那么好
// 2、Date提供getxxx函數--上面有在類里面展現出來可以自己看看,然后在底下的函數體內需要修改一下
// 3、友元函數--這里先不講這個
// 4、重載為成員函數--這個我也在類里重載為成員函數了,但是有些需要注意的地方,我最后選取這種
//bool operator==(const Date& d1, const Date& d2)
//{
//	return d1._year == d2._year//如果用了Get**就是這樣寫的:d1.Getyear() == d2.Getyear()
//		&& d1._month == d2._month
//		&& d1._day == d2._day;
//}int main()
{Date d1(2025,8,1);Date d2(2025,10,1);Date d3(2025, 8, 1);//我們在這里就需要實現運算符重載函數d1 == d2;//運算符重載函數可以顯示調用//operator==(d1, d2);//如果成成員函數了,顯示調用是這樣的//d1.operator==(d2);//只要傳一個參d2就行,d1通過this指針,但是不能在實參和形參顯示寫出來的//再加上運算符重載要求參數個數和運算符作用對象一樣多,所以只能傳一個//可以具體去看看上面類里面怎么實現的cout << (d1 == d2) << '\n';//這里需要打括號,優先級的問題,0cout << (d1 == d3) << '\n';//1return 0;
}

--0表示不相等,1表示相等?

給大家大概看一下 .* 這個符號:(注意注釋)

// .*符號普及,了解即可,剛好提到了這個運算符不能重載
#include<iostream>
using namespace std;void func1()
{cout << "void func()" << endl;
}class A
{
public:void func2(){cout << "A::func()" << endl;}
};int main()
{// 普通函數指針void(*pf1)() = func1;(*pf1)();// A類型成員函數的指針void(A::*pf2)() = &A::func2;A aa;(aa.*pf2)();//這里就是使用的.*return 0;
}

賦值運算符重載:

賦值運算符重載是一個默認成員函數,用于完成兩個已經存在的對象直接的拷貝賦值,這里要注意跟拷貝構造區分,拷貝構造用于?個對象拷貝初始化給另一個要創建的對象。

賦值運算符重載的特點:

  1. 賦值運算符重載是?個運算符重載,規定必須重載為成員函數。賦值運算重載的參數建議寫成const 當前類類型引用,否則會傳值傳參會有拷貝(const還可以有效防止權限擴大,讓能傳的參選擇更多)
  2. 有返回值,且建議寫成當前類類型引用,引用返回可以提高效率,有返回值目的是為了支持連續賦值的場景。
  3. 沒有顯式實現時,編譯器會自動生成?個默認賦值運算符重載,默認賦值運算符重載行為跟默認拷貝構造函數類似,對內置類型成員變量會完成值拷貝/淺拷貝(?個字節?個字節的拷貝),對自定義類型成員變量會調用他的賦值重載函數。
  4. 像Date這樣的類成員變量全是內置類型且沒有指向什么資源,編譯器自動生成的賦值運算符重載就可以完成需要的拷貝,所以不需要我們顯?實現賦值運算符重載。像Stack這樣的類,雖然也都是內置類型,但是_a指向了資源,編譯器自動生成的賦值運算符重載完成的值拷貝/淺拷貝不符合我們的需求,所以需要我們自己實現深拷貝(對指向的資源也進行拷貝)。像MyQueue這樣的類型內部主要是自定義類型Stack成員,編譯器自動生成的賦值運算符重載會調用Stack的賦值運算符重載,也不需要我們顯示實現MyQueue的賦值運算符重載。這里還有?個小技巧,如果?個類顯示實現了析構并釋放資源,那么他就需要顯示寫賦值運算符重載,否則就不需要(跟拷貝構造函數類似)。

--上述特點大部分會在后續的舉例說明中解釋

舉例說明:(注意注釋)?

//賦值運算符重載
#include<iostream>
using namespace std;class Date 
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}//傳引用返回可以減少拷貝(之前提到過在這里傳值返回是自動調用拷貝函數的)//這里能使用是傳引用返回是因為第一個參數用this來的,函數棧幀銷毀也不會找不到//函數要返回類型是為例更好處理連續賦值的情況(d3=d1=d2),用void不好處理Date& operator=(const Date& d)//const和傳引用傳參的作用就不再多說了{//自己等于自己就可以不用賦值了if (this != &d){_year = d._year;_month = d._month;_day = d._day;}//比如:d1=d2表達式的返回對象應該為d1,也就是*thisreturn *this;}//賦值運算符重載,但其實在Date類型里面不寫也沒影響,跟拷貝構造函數處理內置類型原理一樣//思考聯想方法也一樣,不再說了void Print(){cout << _year << "/" << _month << "/" << _day << '\n';}
private:int _year;int _month;int _day;
};int main()
{Date d1;Date d2(2025, 8, 1);d1 = d2;Date d3;d3 = d1 = d2;//從右往左d1.Print();d2.Print();d3.Print();// 需要注意這里是拷?構造,不是賦值重載// 要牢牢記住賦值重載完成兩個已經存在的對象直接的拷?賦值// 而拷?構造用于一個對象拷?初始化給另?個要創建的對象Date d4 = d1;//因為拷貝構造如果寫出這樣就有點容易混//Date d4(d1);//寫成這樣的時候不太容易混淆return 0;
}

完整源代碼:?

cpp-exclusive-warehouse: 【CPP知識學習倉庫】 - Gitee.com


往期回顧:

《吃透 C++ 類和對象(上):封裝、實例化與 this 指針詳解》

《吃透 C++ 類和對象(中):構造函數與析構函數的核心邏輯》

結語:本篇博客就到此結束了,在學完類和對象的這些知識后,雖然還沒學完,但博主后續會先更新實現一個完整的日期類的博客,這個還是有點難度的。大家可以看完之后自己去試一下,檢驗一下自己的學習成果,如果文章對你有幫助的話,歡迎評論,點贊,收藏加關注,感謝大家的支持。

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

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

相關文章

Python 環境隔離實戰:venv、virtualenv 與 conda 的差異與最佳實踐

那天把項目部署到測試環境&#xff0c;結果依賴沖突把服務拉崩了——本地能跑&#xff0c;線上不能跑。折騰半天才發現&#xff1a;我和同事用的不是同一套 site-packages&#xff0c;版本差異導致運行時異常。那一刻我徹底明白&#xff1a;虛擬環境不是可選項&#xff0c;它是…

[ 數據結構 ] 時間和空間復雜度

1.算法效率算法效率分析分為兩種 : ①時間效率, ②空間效率 時間效率即為 時間復雜度 , 時間復雜度主要衡量一個算法的運行速度空間效率即為 空間復雜度 , 空間復雜度主要衡量一個算法所需要的額外空間2.時間復雜度2.1 時間復雜度的概念定義 : 再計算機科學中 , 算法的時間復雜…

一,設計模式-單例模式

目的設計單例模式的目的是為了解決兩個問題&#xff1a;保證一個類只有一個實例這種需求是需要控制某些資源的共享權限&#xff0c;比如文件資源、數據庫資源。為該實例提供一個全局訪問節點相較于通過全局變量保存重要的共享對象&#xff0c;通過一個封裝的類對象&#xff0c;…

AIStarter修復macOS 15兼容問題:跨平臺AI項目管理新體驗

AIStarter是全網唯一支持Windows、Mac和Linux的AI管理平臺&#xff0c;為開發者提供便捷的AI項目管理體驗。近期&#xff0c;熊哥在視頻中分享了針對macOS 15系統無法打開AIStarter的修復方案&#xff0c;最新版已完美兼容。本文基于視頻內容&#xff0c;詳解修復細節與使用技巧…

LabVIEW 紡織檢測數據傳遞

基于 LabVIEW 實現紡織檢測系統中上位機&#xff08;PC 機&#xff09;與下位機&#xff08;單片機&#xff09;的串口數據傳遞&#xff0c;成功應用于煮繭機溫度測量系統。通過采用特定硬件架構與軟件設計&#xff0c;實現了溫度數據的高效采集、傳輸與分析&#xff0c;操作簡…

ECCV-2018《Variational Wasserstein Clustering》

核心思想 該論文提出了一個基于最優傳輸(optimal transportation) 理論的新型聚類方法&#xff0c;稱為變分Wasserstein聚類(Variational Wasserstein Clustering, VWC)。其核心思想有三點&#xff1a;建立最優傳輸與k-means聚類的聯系&#xff1a;作者指出k-means聚類問題本質…

部署 Docker 應用詳解(MySQL + Tomcat + Nginx + Redis)

文章目錄一、MySQL二、Tomcat三、Nginx四、Redis一、MySQL 搜索 MySQL 鏡像下載 MySQL 鏡像創建 MySQL 容器 docker run -i -t/d -p 3307:3306 --namec_mysql -v $PWD/conf:/etc/mysql/conf.d -v $PWD/logs:/logs -v $PWD/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD123456 m…

VR全景導覽在大型活動中的應用實踐:優化觀眾體驗與現場管理

大型演出賽事往往吸引海量觀眾&#xff0c;但復雜的場館環境常帶來諸多困擾&#xff1a;如何快速找到座位看臺區域&#xff1f;停車位如何規劃&#xff1f;附近公交地鐵站在哪&#xff1f;這些痛點直接影響觀眾體驗與現場秩序。VR全景技術為解決這些問題提供了有效方案。通過在…

OpenJDK 17 JIT編譯器堆棧分析

##堆棧(gdb) bt #0 PhaseOutput::safepoint_poll_table (this0x7fffd0bfb950) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/opto/output.hpp:173 #1 0x00007ffff689634e in PhaseOutput::fill_buffer (this0x7fffd0bfb950, cb0x7fffd0bfb970, blk_starts0x7fffb0…

功能測試中常見的面試題-二

二、測試設計與用例編寫題解釋等價類劃分 (Equivalence Partitioning) 和邊界值分析 (Boundary Value Analysis)&#xff1f;并舉例說明。等價類劃分 (EP)&#xff1a; 將輸入域劃分為若干組&#xff08;等價類&#xff09;&#xff0c;假設同一組內的數據對揭露程序錯誤具有等…

SOLi-LABS Page-4 (Challenges)--54-65關

sql-54 翻譯一下頁面&#xff0c;得知我們只有十次機會。id參數是單引號閉合。 ?id-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schemadatabase()-- 我得到的表名是igsyiz2p7z。&#xff08;每個人得到的應該都不一樣&#…

docker代碼如何在vscod上修改

基于 docker-compose.yml文件&#xff08;包含 ??emqx??&#xff08;MQTT服務&#xff09;、??backend??&#xff08;后端服務&#xff09;、??mysql??&#xff08;數據庫&#xff09;&#xff09;的詳細運行、調試、增改刪操作說明&#xff0c;結合流程圖示意&…

HTML5 CSS3 從入門到精通:構建現代Web的藝術與科學

本文將帶你系統地學習掌握現代Web前端的基礎與核心&#xff0c;最終能夠獨立構建語義清晰、布局靈活、交互豐富的專業級網站。 第一章&#xff1a;夯實基礎 - HTML5語義化與結構藝術 1.1 告別<div>混沌&#xff1a;語義化標簽的力量 <header><h1>網站標題…

C# 微軟依賴注入 (Microsoft.Extensions.DependencyInjection) 詳解

文章目錄 前言 核心原理 三大生命周期 核心接口與類 基礎使用示例 關鍵特性詳解 1、構造函數注入 2、作用域管理 3、服務解析方法 4、延遲加載 常見問題解決 問題1:循環依賴 問題2:多實現選擇 性能優化技巧 擴展方法示例 前言 微軟的依賴注入框架是 .NET Core/5+ 的核心組件…

【車聯網kafka】Kafka核心架構與實戰經驗(第四篇)

一、社團扛把子不為人知的秘密 香港社團里&#xff0c;Kafka 是整個組織的名號&#xff0c;ZooKeeper 就是說一不二的長老團&#xff0c;各個片區的 “話事人” 就是 broker&#xff0c;而能統領所有片區的 “扛把子”&#xff0c;就是 Kafka 里的控制器。? 1.1 選舉的秘密 每…

Scala重點(基礎、面向對象、高階函數、集合、模式匹配)

1. 基礎語法1.1. 注釋和java一樣我是單行注釋 /* 我是多行注釋 我是多行注釋 */ /** * 我是文檔注釋 * 我是文檔注釋 */1.2. 語句語句可以不以分號結尾一條語句獨占一行 println("Hello World!")多條語句在一行 println("Hello World!"); println("He…

明遠智睿T113-i核心板:工業設備制造領域的革新利器

在工業設備制造這片充滿挑戰與機遇的領域&#xff0c;技術革新如同一股洶涌浪潮&#xff0c;不斷重塑著市場競爭的格局。隨著技術持續進步&#xff0c;市場競爭愈發激烈&#xff0c;制造商們面臨著如何在保證產品卓越性能的同時&#xff0c;有效控制成本這一關鍵難題。在此背景…

122-基于Flask的校園霸凌數據可視化分析系統

校園霸凌數據可視化分析系統 - 基于Flask的全棧數據分析平臺 本文詳細介紹了一個基于Flask框架開發的校園霸凌數據可視化分析系統&#xff0c;從技術架構到功能實現&#xff0c;為數據分析項目開發提供參考。 &#x1f4cb; 目錄 項目概述技術架構核心功能代碼結構技術棧詳解核…

Docker 網絡設置方式詳解

Docker 網絡是容器通信的核心基礎&#xff0c;它允許容器之間、容器與主機之間以及容器與外部網絡之間進行數據交互。Docker 提供了多種網絡驅動類型&#xff0c;適用于不同場景&#xff0c;下面詳細介紹 Docker 網絡的設置方式。一、Docker 網絡的基本概念 Docker 網絡通過驅動…

export default和export function的作用及export的含義

在 JavaScript 中&#xff0c;export 是一個關鍵字&#xff0c;用于將模塊中的變量、函數、類等導出&#xff0c;以便其他模塊可以導入和使用。export default 和 export&#xff08;非默認導出&#xff09;是兩種不同的導出方式&#xff0c;它們在使用場景和語義上有明顯的區別…