??
???????????????????????????????????????????博主主頁:LiUEEEEE
??????????????????? ????????????????????????????C++專欄
??????????????????? ??????????????????????????C語言專欄
????????????????????????????????????????????數據結構專欄
????????????????????????????????????????????排序算法專欄
?????????????????????????????????????????力扣牛客經典題目專欄
目錄
- 1、前言
- 2、構造函數
- 3、構造函數
- 4、拷貝函數
- 5、結語
1、前言
??在C++中,類擁有六個默認成員函數(使用者如果沒有顯式實現此函數,在C++編譯過程中編譯器也會自動生成),如下:
??本文主要講述其中的三個默認成員函數,分別為構造函數,析構函數,和拷貝構造函數,下面進入正文。
2、構造函數
??例如Data類,其構造函數如下所示:
class Data
{
public://方法1Data(){_year = 1;_month = 1;_day = 1;}//方法2Data(int year, int month, int day){_year = year;_month = month;_day = day;}//方法3Data(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
??根據代碼塊所示,構造函數的目的就是為了將類中成員變量的值進行初始化,而代碼塊中所展示了三種不同的寫法,展示了構造函數的特征:
- 函數名與類名相同。
- 無返回值。
- 對象實例化時編譯器自動調用對應的構造函數。
- 構造函數可以重載。
??方法3的使用方式為,在創建類對象時,在對象后傳入想要初始化的值,例如:
Data data(2024, 7, 2);
??而作為無參的初始化類成員,將默認調用無參數的構造函數,正如上文中提及的特征3一樣。
??值得注意的是,即使構造函數可以重載,以應對不同的初始化要求,但代碼塊中所展示的方法3和方法1不可以同時出現,因為當使用者創建類時:
Data data;
??
??編譯器會去類中尋找使用者顯式實現的無參類型構造函數,但對于全缺省類型的構造函數也可以不傳遞參數進行類對象的創建,此時編譯器就出現了調用沖突,不知道使用者想調用的構造函數是哪一個。
??在C++中,如果使用者沒有顯式實現構造函數,那么C++默認生成的構造函數在調用時并不會對內置類型(編譯器中自帶的類型:int , double , char 等)進行初始化(主要取決于編譯器,在最新版編譯器中可能會將相關成員變量初始化為特定的值),但對于自定義類型,會調用其無參的構造函數(例如:全缺省的構造函數,無參的構造函數,編譯器自動生成的構造函數。 注意以上三種無參構造函數在類中只能存在一個)。
??演示如下:
class Data
{
public:void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Data data;data.Print();return 0;
}
3、構造函數
??對于析構函數,同樣以Data類為例,析構函數的功能與構造函數相反,析構函數不是完成對對象本身的銷毀,局部對象的銷毀工作是由編譯器完成的,而對象在銷毀時會自動調用析構函數,完成對象中資源的清理,類似于在實現棧時的Destroy函數。
??析構函數的特征:
- 析構函數名是在類名前加上字符 “ ~ ”。
- 無參數無返回值類型。
- 一個類只能有一個析構函數。若未顯式定義,系統會自動生成默認的析構函數。注意:析構
函數不能重載 - 對象生命周期結束時,C++編譯系統系統自動調用析構函數。
??樣例如下
class Data
{
public:Data(int year = 2024,int month = 7,int day = 2){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}~Data(){cout << "~Data()" << endl;_year = 1;_month = 1;_day = 1;}
private:int _year;int _month;int _day;
};int main()
{Data data;data.Print();return 0;
}
??因為編譯器在生命周期結束時自動調用析構函數,故上述代碼塊中在析構函數中添加了打印語句“ cout << “~Data()” << endl; ”,其打印結果如下:
??可以明確的看到編譯器確實調用了析構函數。
??同樣的,析構函數在調用時不會對內置類型進行處理,對自定義類型的對象會調用其自己的析構函數,此處不再做演示。
4、拷貝函數
??C++中拷貝函數也稱為拷貝構造函數,其主要目的是在初始化時,將某一個類對象的成員值直接拷貝給新的類對象,其使用方法如下:
Data data1;//方法1Data data2(data1);//方法2Data data3 = data1;
??拷貝函數的特征如下:
- 拷貝構造函數是構造函數的一個重載形式。
- 拷貝構造函數的參數只有一個且必須是類類型對象的引用,使用傳值方式編譯器直接報錯,因為會引發無窮遞歸調用。
- 若未顯式定義,編譯器會生成默認的拷貝構造函數。 默認的拷貝構造函數對象按內存存儲按
字節序完成拷貝,這種拷貝叫做淺拷貝,或者值拷貝。
??那如果使用者要顯式實現拷貝函數呢?其代碼如下所示:
Data(Data& d){_year = d._year;_month = d._month;_day = d._day;}
??可以看到在書寫拷貝函數的代碼時,參數部分使用了引用,這是因為在傳遞過程中我們直接將data放在了函數調用的部分,如果不使用引用的話,此處就會發生傳值調用,而C++編譯器默認在發生傳值調用時,會先調用其拷貝函數,而我們的拷貝函數的參數是形參,就會發生無窮無盡的遞歸調用,而編譯器在面對這種情況時會直接報錯。
??其原理類似于在日常使用函數時我們所傳遞的為形參,而形參是實參的一份臨時拷貝,而拷貝函數在形參處,就會發生無窮無盡的遞歸。
??如果使用者不顯式實現拷貝函數,那么編譯器會自動生成,并按照內存存儲按字節序的方式進行拷貝,顯式實現與不實現都是使用者可以選擇的方式,具體情況按照實際需求進行選擇。
5、結語
??十分感謝您觀看我的原創文章。
??本文主要用于個人學習和知識分享,學習路漫漫,如有錯誤,感謝指正。
??如需引用,注明地址。