??博客主頁:小王又困了
??系列專欄:C++
??人之為學(xué),不日近則日退?
??感謝大家點(diǎn)贊??收藏?評(píng)論??
目錄
一、類的六個(gè)個(gè)默認(rèn)成員函數(shù)
??1.1認(rèn)識(shí)默認(rèn)成員函數(shù)?
二、構(gòu)造函數(shù)
??2.1為什么要有構(gòu)造函數(shù)
??2.2構(gòu)造函數(shù)的概念
??2.3構(gòu)造函數(shù)的特性
??2.4編譯器生成的構(gòu)造函數(shù)?
??2.5編譯器生成構(gòu)造函數(shù)的作用?
??2.6默認(rèn)構(gòu)造函數(shù)
三、析構(gòu)函數(shù)
??3.1析構(gòu)函數(shù)的概念
??3.2析構(gòu)函數(shù)的特性
??3.3編譯器生成析構(gòu)函數(shù)的作用
一、類的六個(gè)個(gè)默認(rèn)成員函數(shù)
如果一個(gè)類中什么成員都沒有,簡稱為空類。
空類不是沒有任何用,任何類在什么都不寫時(shí),編譯器會(huì)自動(dòng)生成以下6個(gè)默認(rèn)成員函數(shù)。
??1.1認(rèn)識(shí)默認(rèn)成員函數(shù)?
默認(rèn)成員函數(shù):用戶沒有顯式實(shí)現(xiàn),編譯器會(huì)生成的成員函數(shù)稱為默認(rèn)成員函數(shù)。
?
- 構(gòu)造函數(shù):完成初始化工作。
- 析構(gòu)函數(shù):完成對(duì)空間的清理工作。
- 拷貝構(gòu)造:使用同類對(duì)象初始化創(chuàng)建對(duì)象。
- 賦值重載:把一個(gè)對(duì)象賦值給另外一個(gè)對(duì)象。
- 取地址重載:普通對(duì)象和const對(duì)象取地址,這兩個(gè)很少自己實(shí)現(xiàn)。
二、構(gòu)造函數(shù)
??2.1為什么要有構(gòu)造函數(shù)
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
d1.Init(2022, 7, 5);//調(diào)用初始化函數(shù)
return 0;
}
? ? ?以前我們創(chuàng)建對(duì)象后,都要自己調(diào)用初始化函數(shù),這樣的操作十分麻煩,而且當(dāng)對(duì)象增多時(shí),有些對(duì)象我們可能會(huì)忘記初始化,這時(shí)程序就會(huì)出現(xiàn)錯(cuò)誤。那么能否在創(chuàng)建對(duì)象的時(shí)候,就自動(dòng)對(duì)它初始化。于是,就有了構(gòu)造函數(shù)。
??2.2構(gòu)造函數(shù)的概念
? ? ?構(gòu)造函數(shù)是一個(gè)特殊的成員函數(shù),名字與類名相同,創(chuàng)建類類型對(duì)象時(shí)由編譯器自動(dòng)調(diào)用,以保證每個(gè)數(shù)據(jù)成員都有 一個(gè)合適的初始值,并且在對(duì)象整個(gè)生命周期內(nèi)只調(diào)用一次。
class Date
{
public:
//構(gòu)造函數(shù)
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
void TestDate()
{
Date d1(2015, 1, 1); // 自己調(diào)用構(gòu)造函數(shù)
}
??2.3構(gòu)造函數(shù)的特性
? ? ?構(gòu)造函數(shù)是特殊的成員函數(shù),需要注意的是,構(gòu)造函數(shù)雖然名稱叫構(gòu)造,但是構(gòu)造函數(shù)的主要任務(wù)并不是開空間創(chuàng)建對(duì)象,而是初始化對(duì)象。?
??特性:
- ?函數(shù)名與類名相同。
- ?無返回值。
- ?對(duì)象實(shí)例化時(shí)編譯器自動(dòng)調(diào)用對(duì)應(yīng)的構(gòu)造函數(shù)。
- ?構(gòu)造函數(shù)可以重載。
class Date
{
public:
// 1.無參構(gòu)造函數(shù)
Date()
{}
// 2.帶參構(gòu)造函數(shù)
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
void TestDate()
{
Date d1; // 調(diào)用無參構(gòu)造函數(shù)
Date d2(2015, 1, 1); // 調(diào)用帶參的構(gòu)造函數(shù)
Date d3();//錯(cuò)誤寫法
}
?注意:如果通過無參構(gòu)造函數(shù)創(chuàng)建對(duì)象時(shí),對(duì)象后面不用跟括號(hào),否則就成了函數(shù)聲明。
??2.4編譯器生成的構(gòu)造函數(shù)?
? ? ?如果類中沒有顯式定義構(gòu)造函數(shù),則C++編譯器會(huì)自動(dòng)生成一個(gè)無參的默認(rèn)構(gòu)造函數(shù),一旦用戶顯式定義編譯器將不再生成。
class Date
{
public:
/*
// 如果用戶顯式定義了構(gòu)造函數(shù),編譯器將不再生成
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
*/
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
return 0;
}
? ? ?將Date類中構(gòu)造函數(shù)屏蔽后,代碼可以通過編譯,因?yàn)榫幾g器生成了一個(gè)無參的默認(rèn)構(gòu)造函數(shù)。?將Date類中構(gòu)造函數(shù)放開,代碼編譯失敗,因?yàn)橐坏╋@式定義任何構(gòu)造函數(shù),編譯器將不再 生成默認(rèn)構(gòu)造函數(shù),Date d1;?沒有可以調(diào)用的無參構(gòu)造函數(shù),所以會(huì)失敗。?
??2.5編譯器生成構(gòu)造函數(shù)的作用?
?
?
?? ? ?d1對(duì)象調(diào)用了編譯器生成的默認(rèn)構(gòu)造函數(shù),但是對(duì)象_year、_month、_day,是隨機(jī)值。那這里編譯器生成的默認(rèn)構(gòu)造函數(shù)有什么用呢?
解答:C++把類型分成內(nèi)置類型(基本類型)和自定義類型。內(nèi)置類型就是語言提供的數(shù)據(jù)類型,如:int、char...,自定義類型就是我們使用class、struct、union等自己定義的類型。(所有類型的指針都屬于內(nèi)置類型)。編譯器生成的默認(rèn)構(gòu)造函數(shù),對(duì)內(nèi)置類型不做處理,對(duì)自定義類型,會(huì)去調(diào)用它的默認(rèn)構(gòu)造函數(shù)。
//先定義一個(gè)時(shí)間類
class Time
{
public:
Time()
{
cout << "Time()" << endl;
_hour = 0;
_minute = 0;
_second = 0;
}
private:
int _hour;
int _minute;
int _second;
};
//再定義一個(gè)日期類
class Date
{
private:
// 基本類型(內(nèi)置類型)
int _year;
int _month;
int _day;
// 自定義類型
Time _t;
};
int main()
{
Date d;
return 0;
}
?
? ? ?如上代碼 ,定義了一個(gè)日期類Date,有四個(gè)成員變量,其中_year、_month、_day都是內(nèi)置類型,_t 是自定義類型,它是一個(gè)時(shí)間類Time,Time類中寫了一個(gè)構(gòu)造函數(shù)。運(yùn)行程序,自定義類型調(diào)用了自己的默認(rèn)構(gòu)造函數(shù),對(duì)值進(jìn)行了初始化。這意味著,在創(chuàng)建對(duì)象的時(shí)候,會(huì)去使用編譯器生成的無參默認(rèn)構(gòu)造函數(shù)。
? ? ?C++11 中針對(duì)內(nèi)置類型成員不初始化的缺陷,又打了補(bǔ)丁,即:內(nèi)置類型成員變量在類中聲明時(shí)可以給默認(rèn)值。?
??示例:?
class Date { private: int _year = 2023; int _month = 11; int _day = 16; }; int main() { Date d1; return 0; }
??2.6默認(rèn)構(gòu)造函數(shù)
? ? ?編譯器自動(dòng)生成的構(gòu)造函數(shù)、無參構(gòu)造函數(shù)、全缺省構(gòu)造函數(shù),這三種都叫做默認(rèn)構(gòu)造函數(shù),它們都有一個(gè)共同的特點(diǎn):可以不用傳參。默認(rèn)構(gòu)造函數(shù)只能有一個(gè),后面?zhèn)z,在語法上可以構(gòu)成函數(shù)重載,但是在無參調(diào)用的時(shí)候,會(huì)發(fā)生歧義,出現(xiàn)調(diào)用不明確。
?
//無參構(gòu)造函數(shù)
Date()
{
_year = 2023;
_month = 11;
_day = 16;
}
//全缺省構(gòu)造函數(shù)
Date(int year = 2023, int month = 11, int day = 16)
{
_year = year;
_month = month;
_day = day;
}
注意:要把默認(rèn)構(gòu)造函數(shù)和默認(rèn)成員函數(shù)區(qū)分清楚,默認(rèn)成員函數(shù)是我們不寫編譯器會(huì)自動(dòng)生成的,默認(rèn)構(gòu)造函數(shù)是不需要傳參的構(gòu)造函數(shù)。編譯器生成的構(gòu)造函數(shù),既是默認(rèn)構(gòu)造函數(shù),同時(shí)也是默認(rèn)成員函數(shù)。?
三、析構(gòu)函數(shù)
??3.1析構(gòu)函數(shù)的概念
? ??析構(gòu)函數(shù)與構(gòu)造函數(shù)功能相反,析構(gòu)函數(shù)不是完成對(duì)對(duì)象本身的銷毀,局部對(duì)象銷毀工作是由 編譯器完成的。而對(duì)象在銷毀時(shí)會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù),完成對(duì)象中資源的清理工作。
??3.2析構(gòu)函數(shù)的特性
??特性:
- ?析構(gòu)函數(shù)名是在類名前加上字符 ~。
- ?無參數(shù)無返回值類型。
- ?一個(gè)類只能有一個(gè)析構(gòu)函數(shù)。若未顯式定義,系統(tǒng)會(huì)自動(dòng)生成默認(rèn)的析構(gòu)函數(shù)。
- ?對(duì)象生命周期結(jié)束時(shí),C++編譯系統(tǒng)系統(tǒng)自動(dòng)調(diào)用析構(gòu)函數(shù)。
typedef int DataType;
class Stack
{
public:
Stack(size_t capacity = 3)
{
_array = (DataType*)malloc(sizeof(DataType) * capacity);
if (NULL == _array)
{
perror("malloc申請(qǐng)空間失敗!!!");
return;
}
_capacity = capacity;
_size = 0;
}
void Push(DataType data)
{
// CheckCapacity();
_array[_size] = data;
_size++;
}
// 其他方法...
~Stack()//析構(gòu)函數(shù)
{
if (_array)
{
free(_array);
_array = NULL;
_capacity = 0;
_size = 0;
}
}
private:
DataType* _array;
int _capacity;
int _size;
};
void TestStack()
{
Stack s;
s.Push(1);
s.Push(2);
}
? ? ? Stack中的成員變量_array是在堆區(qū)上申請(qǐng)的空間,這塊空間在程序結(jié)束后不會(huì)自動(dòng)還給操作系統(tǒng),當(dāng)_array清理后,就找不到動(dòng)態(tài)申請(qǐng)的那塊空間,會(huì)造成內(nèi)存泄漏,因此在對(duì)象銷毀前,要通過析構(gòu)函數(shù)去釋放成員變量_array指向的空間,這就是析構(gòu)函數(shù)的作用。
注意:析構(gòu)函數(shù)不能重載
??3.3編譯器生成析構(gòu)函數(shù)的作用
? ? ?編譯器會(huì)自動(dòng)生成的析構(gòu)函數(shù),對(duì)內(nèi)置類型不做處理,對(duì)自定義類型會(huì)去調(diào)用它的析構(gòu)函數(shù)。
class Time
{
public:
~Time()
{
cout << "~Time()" << endl;
}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
private:
// 基本類型(內(nèi)置類型)
int _year = 1970;
int _month = 1;
int _day = 1;
// 自定義類型
Time _t;
};
int main()
{
Date d;
return 0;
}
?
? ? ?main函數(shù)中創(chuàng)建了 Date對(duì)象d,而d中包含4個(gè)成員變量,其中_year, _month, _day三個(gè)是內(nèi)置類型成員,銷毀時(shí)不需要資源清理,最后系統(tǒng)直接將其內(nèi)存回收即可;而_t是Time類對(duì)象,所以在 d 銷毀時(shí),要將其內(nèi)部包含的Time類的_t對(duì)象銷毀,所以要調(diào)用Time類的析構(gòu)函數(shù)。但是: main函數(shù)中不能直接調(diào)用Time類的析構(gòu)函數(shù),實(shí)際要釋放的是Date類對(duì)象,所以編譯器會(huì)調(diào)用Date類的析構(gòu)函數(shù),而Date沒有顯式提供,則編譯器會(huì)給Date類生成一個(gè)默認(rèn)的析構(gòu)函數(shù),目的是在其內(nèi)部調(diào)用Time類的析構(gòu)函數(shù),即當(dāng)Date對(duì)象銷毀時(shí),要保證其內(nèi)部每個(gè)自定義對(duì)象都可以正確銷毀。
??總結(jié):
? ? 一般情況下,有動(dòng)態(tài)申請(qǐng)資源,就需要顯式的寫析構(gòu)函數(shù)來釋放資源,比如Stack類。沒有動(dòng)態(tài)申請(qǐng)的資源,可以不寫析構(gòu)函數(shù),直接使用編譯器生成的默認(rèn)析構(gòu)函數(shù),比如 Date類。需要釋放資源的成員都是自定義類型,也不需要寫析構(gòu)函數(shù)。
??結(jié)語:?文章來源:http://www.zghlxwxcb.cn/news/detail-752534.html
? ? ?本次的內(nèi)容到這里就結(jié)束啦。希望大家閱讀完可以有所收獲,同時(shí)也感謝各位讀者三連支持。文章有問題可以在評(píng)論區(qū)留言,博主一定認(rèn)真認(rèn)真修改,以后寫出更好的文章。你們的支持就是博主最大的動(dòng)力。文章來源地址http://www.zghlxwxcb.cn/news/detail-752534.html
到了這里,關(guān)于『C++成長記』構(gòu)造函數(shù)和析構(gòu)函數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!