【C++那些事兒】深入理解C++類與對象:從概念到實踐(中)| 默認構造函數 | 拷貝構造函數 | 析構函數 | 運算符重載 | const成員函數

在這里插入圖片描述

📷 江池俊: 個人主頁
🔥個人專欄: ?數據結構冒險記 ?C++那些事兒
🌅 有航道的人,再渺小也不會迷途。


在這里插入圖片描述

文章目錄

    • 1. 類的6個默認成員函數
    • 2. 構造函數
      • 2.1 概念
      • 2.2 特性
    • 3. 析構函數
      • 3.1 概念
      • 3.2 特性
    • 4. 拷貝構造函數
      • 4.1 概念
      • 4.2 特征
    • 5. 運算符重載
      • 5.1 運算符重載
      • 5.2 賦值運算符重載
        • 1. 賦值運算符重載格式
        • 2. 賦值運算符只能重載成類的成員函數不能重載成全局函數
        • 3. 用戶沒有顯式實現時,編譯器會生成一個默認賦值運算符重載,以值的方式逐字節拷貝。
      • `PS:拷貝構造和賦值重載的區分`
      • 5.3 前置++和后置++重載
    • 6. const 修飾的成員函數
      • const 的易錯點:
    • 7. 取地址及const取地址操作符重載
    • 默認生成的成員函數行為總結

1. 類的6個默認成員函數

如果一個類中什么成員都沒有,簡稱為空類。

空類中真的什么都沒有嗎?并不是,任何類在什么都不寫時,編譯器會自動生成以下6個默認成員函數。

默認成員函數:用戶沒有顯式實現,編譯器會生成的成員函數稱為默認成員函數。

在這里插入圖片描述


2. 構造函數

2.1 概念

對于以下Date類:

class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1;d1.Init(2022, 7, 5);d1.Print();Date d2;d2.Init(2022, 7, 6);d2.Print();return 0;
}

對于Date類,可以通過 Init 公有方法給對象設置日期,但如果每次創建對象時都調用該方法設置信息,未免有點麻煩,那能否在對象創建時,就將信息設置進去呢?

構造函數是一個特殊的成員函數,名字與類名相同,創建類類型對象時由編譯器自動調用,以保證每個數據成員都有 一個合適的初始值,并且在對象整個生命周期內只調用一次

2.2 特性

構造函數是特殊的成員函數,需要注意的是,構造函數雖然名稱叫構造,但是構造函數的主要任務并不是開空間創建對象,而是初始化對象

其特征如下

  1. 函數名與類名相同。
  2. 無返回值。
  3. 對象實例化時編譯器自動調用對應的構造函數。
  4. 構造函數可以重載。
class Date
{
public:// 1.無參構造函數Date(){}// 2.帶參構造函數Date(int year, int month, int day){_year = year;  _month = month;_day = day;}
private:int _year;int _month;int _day;
};void TestDate()
{Date d1; // 調用無參構造函數Date d2(2015, 1, 1); // 調用帶參的構造函數// 注意:如果通過無參構造函數創建對象時,對象后面不用跟括號,否則就成了函數聲明// 以下代碼的函數:聲明了d3函數,該函數無參,返回一個日期類型的對象// warning C4930: “Date d3(void)”: 未調用原型函數(是否是有意用變量定義的?)Date d3();
}
  1. 如果類中沒有顯式定義構造函數,則C++編譯器會自動生成一個無參的默認構造函數,一旦用戶顯式定義編譯器將不再生成。
class Date
{
public:/*// 如果用戶顯式定義了構造函數,編譯器將不再生成Date(int year, int month, int day){_year = year;_month = month;_day = day;}*/void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};int main()
{// 將Date類中構造函數屏蔽后,代碼可以通過編譯,因為編譯器生成了一個無參的默認構造函數// 將Date類中構造函數放開,代碼編譯失敗,因為一旦顯式定義任何構造函數,編譯器將不再生成// 無參構造函數,放開后報錯:error C2512: “Date”: 沒有合適的默認構造函數可用Date d;return 0;
}
  1. 關于編譯器生成的默認成員函數,大家可能會有疑惑:不實現構造函數的情況下,編譯器會生成默認的構造函數。但是看起來默認構造函數又沒什么用?上述代碼中d對象調用了編譯器生成的默認構造函數,但是d對象_year/_month/_day,依舊是隨機值。也就說在這里編譯器生成的默認構造函數并沒有什么用??
    在這里插入圖片描述
    解答:C++把類型分成內置類型(基本類型)自定義類型。內置類型就是語言提供的數據類型,如:int/char…,自定義類型就是我們使用class/struct/union等自己定義的類型,看看下面的程序,就會發現編譯器生成默認的構造函數會對自定類型成員_t調用的它的默認構造函數。
class Time
{
public:Time(){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}
private:int _hour;int _minute;int _second;
};class Date
{
private:// 基本類型(內置類型)int _year;int _month;int _day;// 自定義類型Time _t;
};int main()
{Date d;return 0;
}

在這里插入圖片描述

注意:C++11 中針對內置類型成員不初始化的缺陷,又打了補丁,即:內置類型成員變量在類中聲明時可以給默認值

如下:將以上的Date類的成員變量給定默認值。

class Date
{
private:// 基本類型(內置類型)int _year = 1970;int _month = 1;int _day = 1;// 自定義類型Time _t;
};

在這里插入圖片描述
7. 無參的構造函數和全缺省的構造函數都稱為默認構造函數,并且默認構造函數只能有一個。
注意:無參構造函數、全缺省構造函數、我們沒寫編譯器默認生成的構造函數,都可以認為是默認構造函數。

class Date
{
public:Date(){_year = 1900;_month = 1;_day = 1;}Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;
};// 以下測試函數能通過編譯嗎?
void Test()
{Date d1;
}
// 毫無疑問,以上代碼不能通過編譯

在這里插入圖片描述


3. 析構函數

3.1 概念

通過前面構造函數的學習,我們知道一個對象是怎么來的,那一個對象又是怎么沒呢的?

析構函數:與構造函數功能相反,析構函數不是完成對對象本身的銷毀,局部對象銷毀工作是由編譯器完成的。而對象在銷毀時會自動調用析構函數,完成對象中資源的清理工作

3.2 特性

析構函數是特殊的成員函數,其特征如下:

  1. 析構函數名是在類名前加上字符 ~。
  2. 無參數無返回值類型。
  3. 一個類只能有一個析構函數。若未顯式定義,系統會自動生默認的析構函數。注意:析構函數不能重載
  4. 對象生命周期結束時,C++編譯系統系統自動調用析構函數。
typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 3){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申請空間失敗!!!");return;}_capacity = capacity;_size = 0;}void Push(DataType data){// CheckCapacity();_array[_size] = data;_size++;}// 其他方法...~Stack(){if (_array){free(_array);_array = NULL;_capacity = 0;_size = 0;}}private:DataType* _array;int _capacity;int _size;
};int main()
{Stack s;s.Push(1);s.Push(2);return 0;
}

在這里插入圖片描述
在這里插入圖片描述
結論:析構函數的調用順序與構造函數相反,先構造的后析構。其具體調用順序如下:

局部對象(后定義先析構)--> 局部的靜態對象 --> 全局對象(后定義先析構)

  1. 關于編譯器自動生成的析構函數,是否會完成一些事情呢?下面的程序我們會看到,編譯器生成的默認析構函數,對自定類型成員調用它的析構函數。
class Time
{
public:~Time(){cout << "~Time()" << endl;}private:int _hour;int _minute;int _second;
};class Date
{
private:// 基本類型(內置類型)int _year = 1970;int _month = 1;int _day = 1;// 自定義類型Time _t;
};int main()
{Date d;return 0;
}
// 程序運行結束后輸出:~Time()
// 在main方法中根本沒有直接創建Time類的對象,為什么最后會調用Time類的析構函數?
// 因為:main方法中創建了Date對象d,而d中包含4個成員變量,其中_year, _month, _day三個是
// 內置類型成員,銷毀時不需要資源清理,最后系統直接將其內存回收即可;而_t是Time類對象,所以在
// d銷毀時,要將其內部包含的Time類的_t對象銷毀,所以要調用Time類的析構函數。但是:main函數
// 中不能直接調用Time類的析構函數,實際要釋放的是Date類對象,所以編譯器會調用Date類的析構函
// 數,而Date沒有顯式提供,則編譯器會給Date類生成一個默認的析構函數,目的是在其內部調用Time
// 類的析構函數,即當Date對象銷毀時,要保證其內部每個自定義對象都可以正確銷毀
// main函數中并沒有直接調用Time類析構函數,而是顯式調用編譯器為Date類生成的默認析構函數
// 注意:創建哪個類的對象則調用該類的析構函數,銷毀哪個類的對象則調用該類的析構函數

在這里插入圖片描述
6. 如果類中沒有申請資源時,析構函數可以不寫,直接使用編譯器生成的默認析構函數,比如Date類;有資源申請時,一定要寫,否則會造成資源泄漏,比如Stack類。


4. 拷貝構造函數

4.1 概念

在現實生活中,可能存在一個與你一樣的自己,我們稱其為雙胎。
在這里插入圖片描述
那在創建對象時,可否創建一個與已存在對象一某一樣的新對象呢?

拷貝構造函數只有單個形參,該形參是對本類類型對象的引用(一般常用const修飾),在用已存在的類類型對象創建新對象時由編譯器自動調用

4.2 特征

拷貝構造函數也是特殊的成員函數,其特征如下:

  1. 拷貝構造函數是構造函數的一個重載形式
  2. 拷貝構造函數的參數只有一個且必須是類類型對象的引用,使用傳值方式編譯器直接報錯,因為會引發無窮遞歸調用。
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// Date(const Date& d)   // 正確寫法Date(const Date d)   // 錯誤寫法:編譯報錯,會引發無窮遞歸{_year = d._year;_month = d._month;_day = d._day;}private:int _year;int _month;int _day;
};int main()
{Date d1;Date d2(d1); // 拷貝構造:同類型的一個已經存在的對象去初始化一個新的要創建的對象return 0;
}

若使用傳值的方式,在實參傳給形參時就需要調用拷貝構造(即用實參構造一個形參對象),故每次調用拷貝構造函數都需要再次調用拷貝構造函數處理參數的傳遞,因此,這會引發無限遞歸。

在這里插入圖片描述
3. 若未顯式定義,編譯器會生成默認的拷貝構造函數。 默認的拷貝構造函數對象按內存存儲按字節序完成拷貝,這種拷貝叫做淺拷貝,或者值拷貝。

class Time
{
public:Time(){_hour = 1;_minute = 1;_second = 1;}Time(const Time& t){_hour = t._hour;_minute = t._minute;_second = t._second;cout << "Time::Time(const Time&)" << endl;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本類型(內置類型)int _year = 1970;int _month = 1;int _day = 1;// 自定義類型Time _t;
};int main()
{Date d1;// 用已經存在的d1拷貝構造d2,此處會調用Date類的拷貝構造函數// 但Date類并沒有顯式定義拷貝構造函數,則編譯器會給Date類生成一個默認的拷貝構造函數Date d2(d1);return 0;
}

注意:在編譯器生成的默認拷貝構造函數中,內置類型是按照字節方式直接拷貝的,而自定義類型是調用其拷貝構造函數完成拷貝的

  1. 編譯器生成的默認拷貝構造函數已經可以完成字節序的值拷貝了,還需要自己顯式實現嗎?當然像日期類這樣的類是沒必要的。那么下面的類呢?驗證一下試試?
// 這里會發現下面的程序會崩潰掉。這就需要使用深拷貝去解決。
typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 10){_array = (DataType*)malloc(capacity * sizeof(DataType));if (nullptr == _array){perror("malloc申請空間失敗");return;}_size = 0;_capacity = capacity;}void Push(const DataType& data){// CheckCapacity();_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}
private:DataType* _array;size_t _size;size_t _capacity;
};
int main()
{Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2(s1);return 0;
}

在這里插入圖片描述

注意:類中如果沒有涉及資源申請時,拷貝構造函數是否寫都可以;一旦涉及到資源申請時,則拷貝構造函數是一定要寫的,否則就是淺拷貝

  1. 拷貝構造函數典型調用場景:
    • 使用已存在對象創建新對象
    • 函數參數類型為類類型對象
    • 函數返回值類型為類類型對象
class Date
{
public:Date(int year, int minute, int day){cout << "Date(int,int,int):" << this << endl;}Date(const Date& d){cout << "Date(const Date& d):" << this << endl;}~Date(){cout << "~Date():" << this << endl;}
private:int _year;int _month;int _day;
};Date Test(Date d)
{Date temp(d);return temp;
}

在這里插入圖片描述

為了提高程序效率,一般對象傳參時,盡量使用引用類型,返回時根據實際場景,能用引用盡量使用引用


5. 運算符重載

5.1 運算符重載

C++為了增強代碼的可讀性引入了運算符重載,運算符重載是具有特殊函數名的函數,也具有其返回值類型,函數名字以及參數列表,其返回值類型與參數列表與普通的函數類似。

函數名字為:關鍵字operator后面接需要重載的運算符符號

函數原型返回值類型 operator操作符(參數列表)

注意

  • 不能通過連接其他符號來創建新的操作符:比如operator@
  • 重載操作符必須有一個類類型參數
  • 用于內置類型的運算符,其含義不能改變,例如:內置的整型+,不能改變其含義
  • 作為類成員函數重載時,其形參看起來比操作數數目少1,因為成員函數的第一個參數為隱藏的this
  • .* :: sizeof ?: . 注意以上5個運算符不能重載。這個經常在筆試選擇題中出現。
  1. 重載成全局的運算符
// 全局的operator==
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//private:int _year;int _month;int _day;
};// 這里會發現運算符重載成全局的就需要成員變量是公有的,那么問題來了,封裝性如何保證?
// 這里其實可以用后面學習的友元解決,或者干脆重載成成員函數。
bool operator==(const Date& d1, const Date& d2)
{return d1._year == d2._year&& d1._month == d2._month&& d1._day == d2._day;
}void Test()
{Date d1(2018, 9, 26);Date d2(2018, 9, 27);cout << (d1 == d2) << endl;
}
  1. 重載成成員函數的運算符
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// bool operator==(Date* this, const Date& d2)// 這里需要注意的是,左操作數是this,指向調用函數的對象bool operator==(const Date & d2){return _year == d2._year&& _month == d2._month&& _day == d2._day;}
private:int _year;int _month;int _day;
};

5.2 賦值運算符重載

1. 賦值運算符重載格式
  • 參數類型const T&,傳遞引用可以提高傳參效率
  • 返回值類型T&,返回引用可以提高返回的效率,有返回值目的是為了支持連續賦值
  • 檢測是否自己給自己賦值
  • 返回*this :要 復合連續賦值的含義
class Date
{
public:Date(int year = 1900, 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;}// 賦值運算符重載Date& operator=(const Date& d){if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}
private:int _year;int _month;int _day;
};
2. 賦值運算符只能重載成類的成員函數不能重載成全局函數
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}int _year;int _month;int _day;
};// 賦值運算符重載成全局函數,注意重載成全局函數時沒有this指針了,需要給兩個參數
Date& operator=(Date& left, const Date& right)
{if (&left != &right){left._year = right._year;left._month = right._month;left._day = right._day;}return left;
}// 編譯失敗:
// error C2801: “operator =”必須是非靜態成員

在這里插入圖片描述

原因賦值運算符如果不顯式實現,編譯器會生成一個默認的。此時用戶再在類外自己實現一個全局的賦值運算符重載,就和編譯器在類中生成的默認賦值運算符重載沖突了,故賦值運算符重載只能是類的成員函數。
在這里插入圖片描述

3. 用戶沒有顯式實現時,編譯器會生成一個默認賦值運算符重載,以值的方式逐字節拷貝。

注意:內置類型成員變量是直接賦值的,而自定義類型成員變量需要調用對應類的賦值運算符重載完成賦值。

既然編譯器生成的默認賦值運算符重載函數已經可以完成字節序的值拷貝了,還需要自己實現嗎?當然像日期類這樣的類是沒必要的。那么下面的類呢?驗證一下試試?

// 這里會發現下面的程序會崩潰掉。這就需要使用深拷貝去解決。
typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 10){_array = (DataType*)malloc(capacity * sizeof(DataType));if (nullptr == _array){perror("malloc申請空間失敗");return;}_size = 0;_capacity = capacity;}void Push(const DataType& data){// CheckCapacity();_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}private:DataType* _array;size_t _size;size_t _capacity;
};int main()
{Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2;s2 = s1; // 賦值重載:已經存在的兩個對象,一個拷貝賦值給另一個return 0;
}

注意:如果類中未涉及到資源管理,賦值運算符是否實現都可以;一旦涉及到資源管理則必須要實現。

在這里插入圖片描述

PS:拷貝構造和賦值重載的區分

  1. 拷貝構造:同類型的一個已經存在的對象去初始化一個新的要創建的對象。
  2. 賦值重載:已經存在的兩個對象,一個拷貝賦值給另一個。

5.3 前置++和后置++重載

class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// 前置++:返回+1之后的結果// 注意:this指向的對象函數結束后不會銷毀,故以引用方式返回提高效率Date& operator++(){_day += 1;return *this;}// 后置++:// 前置++和后置++都是一元運算符,為了讓前置++與后置++形成能正確的重載// C++規定:后置++重載時多增加一個int類型的參數,但調用函數時該參數不用傳遞,編譯器自動傳遞// 注意:后置++是先使用后+1,因此需要返回+1之前的舊值,故需在實現時需要先將this保存一份,然后給this + 1//       而temp是臨時對象,因此只能以值的方式返回,不能返回引用Date operator++(int){Date temp(*this);_day += 1;return temp;}
private:int _year;int _month;int _day;
};int main()
{Date d;Date d1(2022, 1, 13);d = d1++;    // d: 2022,1,13   d1:2022,1,14d = ++d1;    // d: 2022,1,15   d1:2022,1,15return 0;
}

6. const 修飾的成員函數

將const修飾的“成員函數”稱之為const成員函數,const修飾類成員函數,實際修飾該成員函數隱含的this指針,表明在該成員函數中 不能對類的任何成員進行修改

在這里插入圖片描述

我們來看看下面的代碼:

class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << "Print()" << endl;cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl << endl;}void Print() const{cout << "Print()const" << endl;cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl << endl;}
private:int _year; // 年int _month; // 月int _day; // 日
};void Test()
{Date d1(2022, 1, 13);d1.Print();const Date d2(2022, 1, 13);d2.Print();
}

請思考下面的幾個問題:

  1. const對象可以調用非const成員函數嗎?

不可以,權限放大了。const對象只能調用const成員函數。如果嘗試用const對象調用非const成員函數,編譯器會報錯,因為非const成員函數可能會修改對象的狀態,這與const對象的不可變性是相悖的。

  1. 非const對象可以調用const成員函數嗎?

可以,權限縮小。非const對象既可以調用const成員函數,也可以調用非const成員函數。const成員函數保證不會修改對象的狀態,因此即使是非const對象也可以安全地調用它們。

  1. const成員函數內可以調用其它的非const成員函數嗎?

不可以,權限放大了。const成員函數內部不能調用非const成員函數,因為非const成員函數可能會修改對象的狀態,這與const成員函數不修改對象狀態的約束是沖突的。

  1. 非const成員函數內可以調用其它的const成員函數嗎?

可以,權限縮小。非const成員函數內部可以調用const成員函數,因為const成員函數保證不會修改對象的狀態,即使非const對象調用它們也是安全的。

總結const對象只能調用const成員函數,非const對象可以調用const和非const成員函數。const成員函數內部不能調用非const成員函數,但非const成員函數內部可以調用const成員函數。

const 的易錯點:

void func(const int& x)
{}int main()
{// const修飾:只讀   非const:可讀可寫int a = 0;int& b = a;b++;func(a);// 權限的縮小 --可以的const int& c = a;const int x = 10;// 權限的放大 --不可以的//int& y = x;const int& y = x;// int& z = y;const int& z = 10;const int& m = a + x;// 權限的放大 a+x表達式的返回值是臨時對象。臨時對象具有常性//int& n = a + x;func(10);func(a + x);return 0;
}

7. 取地址及const取地址操作符重載

這兩個默認成員函數一般不用重新定義 ,編譯器默認會生成。

class Date
{
public:Date* operator&(){return this;}const Date* operator&()const{return this;}
private:int _year; // 年int _month; // 月int _day; // 日
};

這兩個運算符一般不需要重載,使用編譯器生成的默認取地址的重載即可,只有特殊情況,才需要重載,比如想讓別人獲取到指定的內容


默認生成的成員函數行為總結

  1. 對于初始化和清理的默認成員函數
    內置類型不處理,自定義類型調用對應的構造和析構。
  2. 對于拷貝復制的默認成員函數
    內置類型值拷貝,自定義類型調用對應的拷貝構造和賦值重載。

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

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

相關文章

國際視頻編解碼標準提案下載地址

H.266 相關提案下載地址&#xff1a;http://phenix.it-sudparis.eu/jvet/ 更新的地址&#xff1a;https://jvet-experts.org/ H.265 提案下載地址&#xff1a;http://phenix.int-evry.fr/jct/ 標準文檔下載地址&#xff1a;http://www.itu.int/rec/T-REC-H.265 H.264 提案下載…

QT多語言切換功能

一.目的 在做項目時&#xff0c;有時希望我們的程序可以在不同的國家使用&#xff0c;這樣最好的方式是一套程序能適應于多國語言。 Qt提供了這樣的功能&#xff0c;使得一套程序可以呈現出不同的語言界面。本文將介紹QT如何實現多語言&#xff0c;以中文和英文為例。 QT開發…

過于老舊的pytorch_ssim包 請從github下載源碼

有些冷門算法真的不要隨便pip&#xff0c;有可能下載到史前版本…最好還是找源代碼 汗 今天要用到SSIM損失函數&#xff0c;從網上簡單看了一下原理就想測試一下&#xff0c;偷了一下懶就直接在命令行輸入pip install pytorch_ssim了&#xff0c;結果報了一堆錯誤&#xff08;汗…

Qt將Unicode轉換成UTF8中文

解析字符串&#xff0c;并將里面的Unicode轉換成中文 QString unicodeToUtf8(QString unicode) {QString result;for (int i 0; i < unicode.length(); i){QString flag unicode.mid(i,2); if (flag "\\u"){QString s1 unicode.mid(i 2, 4);result.append(s…

如何自定義一個spring-boot-starter

在我的理解中&#xff0c;spring-boot-starter就是一個依賴工具包&#xff0c;但是它和普通的依賴又有所區別&#xff0c;那么首先spring-boot-starter-一定是一個spring-boot項目&#xff0c;然后它和一般的依賴有什么區別呢&#xff0c;我們可以在它的resources目錄下定義一個…

Mysql實戰(1)之環境安裝

1&#xff0c;進入&#xff1a;MySQL :: MySQL Downloads 2&#xff0c; 3&#xff0c; 4&#xff0c;

【數據集】中國廣泛時空水質數據集(1980-2022)

中國廣泛時空水質數據集(1980-2022) 1 數據概述1.1 數據細節2 數據下載下載鏈接1:figshare參考1 數據概述 水質數據是評估水生生態系統福祉和確保人類清潔水源的關鍵資源。雖然水質數據集的可用性正在增長,但值得注意的是,中國缺乏可公開訪問的內陸和海洋國家水質數據集。…

Python算法題集_單詞搜索

Python算法題集_單詞搜索 題22&#xff1a;單詞搜索1. 示例說明2. 題目解析- 題意分解- 優化思路- 測量工具 3. 代碼展開1) 標準求解【原始矩陣狀態回溯】2) 改進版一【字典檢測原始矩陣狀態回溯】3) 改進版二【矩陣狀態回溯】 4. 最優算法5. 相關資源 本文為Python算法題集之一…

DM數據庫學習之路(十九)DM8數據庫sysbench部署及壓力測試

sysbench部署 安裝依賴 yum -y install make automake libtool pkgconfig libaio-devel vim-common 上傳sysbench源代碼 sysbench_tool.tar 測試是否安裝成功 $ /opt/sysbench/sysbench-master-dpi/src/lua $ ./sysbench --version sysbench 1.1.0 sysbench測試DM 測試…

jupyter調用envs環境——jupyter內核配置虛擬環境

1.jupyter無法使用envs環境 pycharm的終端打開jupyter notebook&#xff1a; 在kernel下找不到上面的Pytorch_GPU環境&#xff1a; 2.解決方法 在對應的envs環境中安裝ipykernel&#xff1a; 將該環境寫入jupyter&#xff1a; python -m ipykernel install --user --name Py…

基于分位數回歸的長短期記憶神經網絡(QRLSTM)的MATLAB實現(源代碼)

分位數回歸的長短期神經記憶網絡介紹&#xff1a; QRLSTM&#xff08;Quantile Regression Long Short-Term Memory&#xff09;分位數回歸神經網絡是一種結合了長短期記憶&#xff08;LSTM&#xff09;神經網絡和分位數回歸的模型。這種神經網絡結構旨在對數據的不同分位數進行…

Java的四大引用詳解-沖擊金三銀四

強引用 像“Object obj new Object()”這類的引用均為強引用&#xff0c;當一個對象被強引用變量引用時&#xff0c;它處于可達狀態&#xff0c;是不可能被垃圾回收器回收的&#xff0c;即使該對象永遠不會被用到也不會被回收。 當JVM出現內存不足時&#xff0c;JVM進行垃圾回…

繼承-重寫

Phone基類&#xff1a; package ven;public class Phone {public Phone(){}public void call(String name){System.out.println("給"name"打電話");} } AIPhone子類&#xff1a; package ven;public class AIPhone extends Phone{Override //重載注解&am…

mTLS: openssl創建CA證書

證書可以通過openssl或者keytool創建&#xff0c;在本篇文章中&#xff0c;只介紹openssl。 openssl 生成證書 申請操作流程 生成ca證書私鑰, 文件名&#xff1a;ca.key生成ca證書&#xff0c;文件名&#xff1a;ca.crt生成Server/Client 證書私鑰&#xff0c;文件名&#x…

設計模式(十三)抽象工廠模式

請直接看原文:設計模式&#xff08;十三&#xff09;抽象工廠模式_抽象工廠模式告訴我們,要針對接口而不是實現進行設計。( )-CSDN博客 -------------------------------------------------------------------------------------------------------------------------------- …

系統架構設計文檔模版

XX 系統架構設計方案 修訂記錄 日期 版本號 修訂說明 修訂人 審核人 1、概述... 5 1.1&#xff0e;業務背景... 5 1.2&#xff0e;系統總體描述... 5 1.3&#xff0e;系統邊界圖... 5 1.4&#xff0e;名詞和縮略語... 5 1.…

live555源碼學習(1)

1 基礎組件 live項目主要包含了四個基礎庫、程序入口類&#xff08;mediaServer&#xff09;和測試程序&#xff08;testProgs&#xff09;。四個基礎庫是UsageEnvironment、BasicUsageEnvironment、groupsock和liveMedia UsageEnvironment 抽象了兩個類UsageEnvironment和T…

力扣hot5---雙指針

題目&#xff1a; 解決方案&#xff1a;雙指針 指針 i 指向最左側&#xff0c;指針 j 指向最右側。此時在寬度上達到了最大值&#xff0c;那么哪個柱子更矮&#xff0c;哪個柱子向內部移動&#xff0c;知道 i 與 j 相遇。為什么呢&#xff1f; 如果哪個哪個柱子更矮&#xff0c…

代碼隨想錄算法訓練營第四十一天|198.打家劫舍,213.打家劫舍II,337.打家劫舍III

系列文章目錄 代碼隨想錄算法訓練營第一天|數組理論基礎&#xff0c;704. 二分查找&#xff0c;27. 移除元素 代碼隨想錄算法訓練營第二天|977.有序數組的平方 &#xff0c;209.長度最小的子數組 &#xff0c;59.螺旋矩陣II 代碼隨想錄算法訓練營第三天|鏈表理論基礎&#xff…

Node.js基礎---模塊化

基本概念 模塊化 模塊化是指解決一個復雜問題時&#xff0c;自上向下逐層把系統劃分成若干模塊的過程&#xff0c;對于整個系統來說&#xff0c;模塊是可組合&#xff0c;分解和更換的單元 遵守固定規則&#xff0c;把大文件拆分成獨立并互相依賴的多個小模塊 好處&#xff1a…