C++默認成員函式詳解
- 一、建構式
- 1.作用
- 2.函式樣式
- 3.使用特點
- 4.注意事項
- 二、解構式
- 1.作用
- 2.函式樣式
- 3.使用特點
- 4.注意事項
- 三、拷貝建構式
- 1.作用
- 2.函式樣式
- 3.使用特點
- 4.注意事項
- 四、復制運算子多載
- 1.作用
- 2.函式樣式
- 3.使用特點
- 4.注意事項
- 總結
#### c++作為面向物件的編程語言,與c語言相比最大的一個特點就是類的使用,使資料與方法打包(變數與函式打包)在類中,而類中很重要的就是默認成員函式,默認成員函式是幫助我們更好處理物件與記憶體的一種方式,所以我們有必要充分的理解認識它們,這樣才能使我們的代碼更加流暢便捷易讀,
#### 所謂默認成員函式,就是在一個空類中,即使我們什么都不寫,編譯器會自動生成的函式,但是我們也可以自己去寫,實作我們想要做到的功能,這時候,編譯器就會優先使用我們自己實作的默認成員函式,下面將重點介紹四個重要的默認成員函式,
一、建構式
1.作用
####建構式完成的是某一類的一個物件中成員變數的初始化作業,即在物件創建時,編譯器就會自動呼叫建構式,完成類中成員變數的初始化,
2.函式樣式
####建構式有兩種要求,編譯器才會將其作為建構式
(1)函式名必須與類名相同
(2)函式無回傳值(無回傳值不代表是void,void表示有回傳值,回傳值為空)
//示例
class Date
{
public:
Date(int year, int month, int day) //初始化成員變數
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
3.使用特點
(1)建構式在創建物件的時候呼叫,分為兩種呼叫方式,一種是傳值呼叫,一種是默認值呼叫,
(2)給定值呼叫就是在創建物件時,我們將想要成員變數初始化的值當作引數傳給建構式,這個要求建構式形參串列中必須有形參來接受實參,
(3)默認值呼叫就是指在創建物件的時候,我們不需要傳參,在創建物件時直接給定某一默認值來初始化成員變數,這時候建構式我們稱為默認建構式,
(4)默認建構式:默認建構式就是指不用傳參就可以呼叫初始化成員變數的建構式,一共有三種默認建構式,
1.編譯器自動生成的建構式:這類建構式是雙標的,對于成員變數中的內置型別,它會不做任何處理,變數中仍然是隨機值,而對于自定義型別(class、struct、union),編譯器生成的建構式就會呼叫該型別的默認建構式(注意,一定是默認建構式,因為你沒傳值,因此該自定義型別的成員變數就會去呼叫它的型別得到默認建構式去初始化)
2.無參的建構式:函式引數串列中沒有引數
3.全預設的默認建構式:在引數串列中形參全預設,因此在不傳參的情況下就會使用預設值來初始化成員變數,預設的建構式有一個好處,就是即支持傳值呼叫,又支持默認值呼叫,可以在構造物件時傳值來賦予想要的值
//1.不寫編譯器自動生成一個默認建構式
//2.無參的函式
Date()
{
_year = 2000;
_month = 1;
_day = 1;
}
//3.帶有預設值的建構式
Date(int year = 2000, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//建構式的使用
int main()
{
Date d1; //這是使用默認建構式,進行默認值的初始化
Date d2(2021,7,22); //這是進行傳參的初始化
}
4.注意事項
(1)最推薦的建構式型別是全預設的,這樣既可以傳參按照自己的意愿初始化,又可以使用默認建構式,
(2)每個類都必須有默認建構式,自己不寫就會由編譯器自己生成一個,但是編譯器自動生成的默認建構式雙標:內置型別不處理,自定義型別呼叫該型別的默認建構式,因此可能編譯器生成的這個不符合自己的需求,
(3)建構式支持函式多載,這使得可以有多種初始化方式,
二、解構式
1.作用
####解構式完成的是在物件宣告周期接受后自動呼叫進行資源的清理(開辟空間的釋放等)不是完成物件的銷毀,物件的銷毀是在函式堆疊幀銷毀時自動完成的,根本不需要認為處理,
2.函式樣式
####解構式要滿足下面兩個要求,編譯器才會將它當作解構式
(1)函式名為類名前加~
(2)函式無參,無回傳值,
~Date()
{
//資源的清理
}
3.使用特點
(1)解構式在物件生命周期結束后自動呼叫
(2)解構式有且僅有一個,如果為顯示定義,那么作為類的默認成員函式,編譯器會自動生成一個解構式,但是這個解構式也是雙標的:對于內置型別,不會進行任何處理,對于自定義型別,則會呼叫它的解構式,
(3)解構式只有一個,無法函式多載,
(4)對于有些類,像成員變數只有int型別的日期類,解構式就是什么用也沒有,因此我們可以不用寫,用編譯器自己生成的就夠了,但是對于動態開辟的記憶體的成員變數,那么我們必須自己寫來釋放記憶體,因為編譯器自己生成的不會有釋放空間這個功能,
4.注意事項
####因為物件都是在函式堆疊幀上開辟空間的,所以解構式的順序應該符合堆疊的后入先出,即:后創建的物件先析構,
三、拷貝建構式
1.作用
####用已存在的物件來創建新物件,并且使新物件的值與已存在物件的值相同,類似于拷貝,因此稱為拷貝構造,
2.函式樣式
####滿足以下條件,編譯器才將其處理為拷貝建構式,
(1)函式名與類名相同(與建構式形成函式多載)
(2)函式引數只有一個,為同型別物件并且參考傳參.傳值傳參會引發無窮遞回,因為:在傳值的時候,就需要用實參拷貝構造出形參,目的是實作拷貝構造,結果你在實作的程序中使用了拷貝構造,就會無窮遞回
Date(const Date& d)
{
_year = d.-year;
_month = d._month;
_day = d._day;
}
3.使用特點
(1)拷貝構造在創建新物件的時候自動呼叫
(2)在使用編譯器自動生成的時候,對于內置型別會進行淺拷貝,對于自定義型別會呼叫該型別自己的拷貝建構式,
(3)使用方式:
int main()
{
Date d1(2021,7,21);
Date d2 = d1; //一種拷貝構造
Date d2(d1) //另一種拷貝構造
return 0;
}
4.注意事項
####對于編譯器默認生成的拷貝建構式來說,完成的是淺拷貝,對于深淺拷貝問題,是一個比較大的問題,在這里我們暫且先知道,淺拷貝,就是無腦的將值毫無改變的賦值過去,然后就會出現一個問題,就是如果成員變數中有指標,那么指標存盤的地址也是完全一樣的,指向同一塊空間,必然會出現一系列的問題,這個時候我們就需要自己寫拷貝建構式,來完成深拷貝,
四、復制運算子多載
1.作用
####這個函式的功能你可以認為就是物件之間的賦值,就和賦值運算子“ = ”對于內置型別的作用一樣,
2.函式樣式
####符合運算子多載的要求,同時為了支持連續賦值,所以回傳值必須是該型別的參考,引數也是該型別的應用,并且因為不會改變內容,最好加const修飾
Date& operator=(const Data& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
3.使用特點
(1)當需要將一個物件的值給另一個物件的時候可以使用,
(2)自己不寫,在使用編譯器會自動生成,對于內置型別會進行淺拷貝,對于自定義型別會呼叫該型別自己的
賦值運算子多載函式,
(3)使用方式
int main()
{
Date d1(2021,5,6);
Date d2(2024,6,9);
d2 = d1;
}
4.注意事項
(1)賦值多載與拷貝構造的機理完全類似,都會存在淺拷貝存在的問題,因此必要時,還是需要自己寫賦值多載,
(2)不能通過連接其他符號來創建新的運算子:比如operator@,
(3)多載運算子必須有一個型別別或者列舉型別的運算元,
(4)用于內置型別的運算子,其含義不能改變,例如:內置的整型+,不能改變其含義,
(5)作為類成員的多載函式時,其形參看起來比運算元數目少1成員函式的
運算子有一個默認的形參this,限定為第一個形參,
(6).* 、:: 、sizeof 、?: 、. 注意以上5個運算子不能多載,
總結
####其實還有兩個默認成員函式沒提到取地址及const取地址運算子多載但是這兩個使用編譯器默認生成的就足夠了,完全沒必要自己寫,而且也十分簡單,
####總結一下:默認成員函式都是自己不寫編譯器可以自己生成的,但是編譯器生成的很難達到我們想要的那種效果,如:內置型別建構式的初始化、淺拷貝問題因此我們要根據實際情況來實作默認成員函式,來為代碼保駕護航,
####
####
####
####如有錯誤,請指正,謝謝!
####有問題請在評論區留言,我會盡力解答!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/289639.html
標籤:其他
上一篇:js 封裝websocket
