1.類的6個(gè)默認(rèn)成員函數(shù)
如果一個(gè)類中什么成員都沒(méi)有,簡(jiǎn)稱為空類
空類中真的什么都沒(méi)有嗎?并不是,任何類在什么都不寫時(shí),編譯器會(huì)自動(dòng)生成以下6個(gè)默認(rèn)成員函數(shù)
默認(rèn)成員函數(shù):用戶沒(méi)有顯式實(shí)現(xiàn),編譯器會(huì)生成的成員函數(shù)稱為默認(rèn)成員函數(shù)
class Date {};
由于編譯器的優(yōu)化 我們未給_a賦值 這里是不會(huì)報(bào)錯(cuò)的
這里還需要強(qiáng)調(diào)一個(gè)點(diǎn)就是成員函數(shù)的地址不在對(duì)象中
成員變量存放在對(duì)象中
2. 構(gòu)造函數(shù)
我們先來(lái)看兩道經(jīng)典的面試題
這道題首先排除A 因?yàn)閚ullptr屬于運(yùn)行錯(cuò)誤 我們編譯器在編譯的時(shí)候只負(fù)責(zé)檢查語(yǔ)法錯(cuò)誤 nullptr語(yǔ)法是沒(méi)錯(cuò)誤的
這道題是正常運(yùn)行的 但是為什么呢?
這是因?yàn)槌蓡T函數(shù)的地址不在對(duì)象中
成員變量存放在對(duì)象中
第二題
這里選擇B運(yùn)行崩潰
因?yàn)槲覀冞@里涉及到一個(gè)this指針的知識(shí)
this指針為nullptr 所以nullptr指向_a就會(huì)報(bào)錯(cuò)
2.1 概念
對(duì)于以下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;
}
對(duì)于Date類,可以通過(guò) Init 公有方法給對(duì)象設(shè)置日期,但如果每次創(chuàng)建對(duì)象時(shí)都調(diào)用該方法設(shè)置信息,未免有點(diǎn)麻煩,那能否在對(duì)象創(chuàng)建時(shí),就將信息設(shè)置進(jìn)去呢?
構(gòu)造函數(shù)是一個(gè)特殊的成員函數(shù),名字與類名相同,創(chuàng)建類類型對(duì)象時(shí)由編譯器自動(dòng)調(diào)用,以保證每個(gè)數(shù)據(jù)成員都有 一個(gè)合適的初始值,并且在對(duì)象整個(gè)生命周期內(nèi)只調(diào)用一次
2.2 特性
構(gòu)造函數(shù)是特殊的成員函數(shù),需要注意的是,構(gòu)造函數(shù)雖然名稱叫構(gòu)造,但是構(gòu)造函數(shù)的主要任務(wù)并不是開(kāi)空間創(chuàng)建對(duì)象,而是初始化對(duì)象
其特征如下:
- 函數(shù)名與類名相同
- 無(wú)返回值
- 對(duì)象實(shí)例化時(shí)編譯器自動(dòng)調(diào)用對(duì)應(yīng)的構(gòu)造函數(shù)
- 構(gòu)造函數(shù)可以重載
class Date
{
public:
// 1.無(wú)參構(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)用無(wú)參構(gòu)造函數(shù)
Date d2(2015, 1, 1); // 調(diào)用帶參的構(gòu)造函數(shù)
// 注意:如果通過(guò)無(wú)參構(gòu)造函數(shù)創(chuàng)建對(duì)象時(shí),對(duì)象后面不用跟括號(hào),否則就成了函數(shù)聲明
// 以下代碼的函數(shù):聲明了d3函數(shù),該函數(shù)無(wú)參,返回一個(gè)日期類型的對(duì)象
// warning C4930: “Date d3(void)”: 未調(diào)用原型函數(shù)(是否是有意用變量定義的?)
Date d3();
}
- 如果類中沒(méi)有顯式定義構(gòu)造函數(shù),則C++編譯器會(huì)自動(dòng)生成一個(gè)無(wú)參的默認(rèn)構(gòu)造函數(shù),一旦用戶顯式定義編譯器將不再生成
代碼演示和注釋如下
class date
{
public:
// 夠成函數(shù)重載,但是無(wú)參調(diào)用存在歧義,不能同時(shí)存在
/*date()
{
_year = 1;
_month = 1;
_day = 1;
}*/
date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//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;
};
// date f(); 函數(shù)聲明
int main()
{
date d1;
d1.print();
date d2(2023, 10, 19);
d2.print();
date d3(2023, 10);
d3.print();
return 0;
}
6. 關(guān)于編譯器生成的默認(rèn)成員函數(shù),很多童鞋會(huì)有疑惑:不實(shí)現(xiàn)構(gòu)造函數(shù)的情況下,編譯器會(huì)生成默認(rèn)的構(gòu)造函數(shù)。但是看起來(lái)默認(rèn)構(gòu)造函數(shù)又沒(méi)什么用?d對(duì)象調(diào)用了編譯器生成的默認(rèn)構(gòu)造函數(shù),但是d對(duì)象_year/_month/_day,依舊是隨機(jī)值。也就說(shuō)在這里編譯器生成的默認(rèn)構(gòu)造函數(shù)并沒(méi)有什么用??
解答:C++把類型分成內(nèi)置類型(基本類型)和自定義類型。內(nèi)置類型就是語(yǔ)言提供的數(shù)據(jù)類型,如:int/char…,自定義類型就是我們使用class/struct/union等自己定義的類型,看看下面的程序,就會(huì)發(fā)現(xiàn)編譯器生成默認(rèn)的構(gòu)造函數(shù)會(huì)對(duì)自定類型成員_t調(diào)用的它的默認(rèn)成員函數(shù)
大家可曾記得我前面的LeetCode刷題里面講過(guò)一道題就是兩個(gè)棧實(shí)現(xiàn)一個(gè)隊(duì)列嗎 我們構(gòu)造函數(shù)現(xiàn)在就要用這道題來(lái)進(jìn)行驗(yàn)證
class Date
{
public:
// 夠成函數(shù)重載,但是無(wú)參調(diào)用存在歧義,不能同時(shí)存在
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
// 默認(rèn)生成的構(gòu)造函數(shù),啥事都干?
// 處理自定義(會(huì)去調(diào)用這個(gè)成員的默認(rèn)構(gòu)造函數(shù))
// 內(nèi)置類型不確定(看編譯器),建議當(dāng)成不處理
private:
// C++11支持,聲明時(shí)給缺省值
int _year = 1;
int _month = 1;
int _day = 1;
};
class Stack
{
public:
Stack(size_t capacity = 3)
{
cout << "Stack(size_t capacity = 3)" << endl;
_a = (int*)malloc(sizeof(int) * capacity);
if (nullptr == _a)
{
perror("malloc申請(qǐng)空間失敗!!!");
}
_capacity = capacity;
_top = 0;
}
private:
int* _a;
int _capacity;
int _top;
};
// 兩個(gè)棧實(shí)現(xiàn)一個(gè)隊(duì)列
class MyQueue
{
private:
Stack _pushst;
Stack _popst;
int _size = 1;
};
int main()
{
Date d1;
d1.Print();
Stack st1;
MyQueue mq;
return 0;
}
那如果我將棧的初始化那部分注釋掉了會(huì)發(fā)生什么呢?
注釋掉了編譯器不會(huì)默認(rèn)去調(diào)用構(gòu)造函數(shù)進(jìn)行打印的 希望大家能夠理解
這里再給大家強(qiáng)調(diào)一下 看圖片解釋
注意:C++11 中針對(duì)內(nèi)置類型成員不初始化的缺陷,又打了補(bǔ)丁,即:內(nèi)置類型成員變量在類中聲明時(shí)可以給默認(rèn)值
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
// C++11支持,聲明時(shí)給缺省值
int _year = 1;
int _month = 1;
int _day = 1;
};
// 1、我們不寫編譯默認(rèn)生成那個(gè)構(gòu)造函數(shù),叫默認(rèn)構(gòu)造
// 2、無(wú)參構(gòu)造函數(shù)也可以叫默認(rèn)構(gòu)造
// 3、全缺省也可以叫默認(rèn)構(gòu)造
// 可以不傳參數(shù)就調(diào)用構(gòu)造,都可以叫默認(rèn)構(gòu)造
// 這三個(gè)函數(shù)不能同時(shí)存在,只能存在一個(gè)
int main()
{
Date d1;
d1.Print();
return 0;
}
- 無(wú)參的構(gòu)造函數(shù)和全缺省的構(gòu)造函數(shù)都稱為默認(rèn)構(gòu)造函數(shù),并且默認(rèn)構(gòu)造函數(shù)只能有一個(gè)
注意:無(wú)參構(gòu)造函數(shù)、全缺省構(gòu)造函數(shù)、我們沒(méi)寫編譯器默認(rèn)生成的構(gòu)造函數(shù),都可以認(rèn)為是默認(rèn)構(gòu)造函數(shù)
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;
};
// 以下測(cè)試函數(shù)能通過(guò)編譯嗎?
void Test()
{
Date d1;
3.析構(gòu)函數(shù)
3.1 概念
通過(guò)前面構(gòu)造函數(shù)的學(xué)習(xí),我們知道一個(gè)對(duì)象是怎么來(lái)的,那一個(gè)對(duì)象又是怎么沒(méi)呢的?
析構(gòu)函數(shù):與構(gòu)造函數(shù)功能相反,析構(gòu)函數(shù)不是完成對(duì)對(duì)象本身的銷毀,局部對(duì)象銷毀工作是由編譯器完成的。而對(duì)象在銷毀時(shí)會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù),完成對(duì)象中資源的清理工作文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-718315.html
3.2 特性
析構(gòu)函數(shù)是特殊的成員函數(shù),其特征如下:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-718315.html
- 析構(gòu)函數(shù)名是在類名前加上字符 ~
- 無(wú)參數(shù)無(wú)返回值類型
- 一個(gè)類只能有一個(gè)析構(gòu)函數(shù)。若未顯式定義,系統(tǒng)會(huì)自動(dòng)生成默認(rèn)的析構(gòu)函數(shù)。注意:析構(gòu)函數(shù)不能重載
- 對(duì)象生命周期結(jié)束時(shí),C++編譯系統(tǒng)系統(tǒng)自動(dòng)調(diào)用析構(gòu)函數(shù)
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
~Date()
{
// Date嚴(yán)格來(lái)說(shuō),不需要寫析構(gòu)函數(shù)
cout << "~Date()" << endl;
}
private:
// C++11支持,聲明時(shí)給缺省值
int _year = 1;
int _month = 1;
int _day = 1;
};
- 關(guān)于編譯器自動(dòng)生成的析構(gòu)函數(shù),是否會(huì)完成一些事情呢?下面的程序我們會(huì)看到,編譯器生成的默認(rèn)析構(gòu)函數(shù),對(duì)自定類型成員調(diào)用它的析構(gòu)函數(shù)
class Stack
{
public:
Stack(size_t capacity = 3)
{
cout << "Stack(size_t capacity = 3)" << endl;
_a = (int*)malloc(sizeof(int) * capacity);
if (nullptr == _a)
{
perror("malloc申請(qǐng)空間失敗!!!");
}
_capacity = capacity;
_top = 0;
}
~Stack()
{
cout << "~Stack()" << endl;
free(_a);
_capacity = _top = 0;
_a = nullptr;
}
private:
int* _a;
int _capacity;
int _top;
};
class MyQueue
{
// 默認(rèn)生成析構(gòu)函數(shù),行為跟構(gòu)造類似
// 內(nèi)置類型成員不做處理
// 自定義類型成員會(huì)去調(diào)用他的析構(gòu)
private:
Stack _pushst;
Stack _popst;
int _size = 1;
};
int main()
{
//Date d1;
//Stack st1;
MyQueue mq;
return 0;
}
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;
}
// 程序運(yùn)行結(jié)束后輸出:~Time()
// 在main方法中根本沒(méi)有直接創(chuàng)建Time類的對(duì)象,為什么最后會(huì)調(diào)用Time類的析構(gòu)函數(shù)?
// 因?yàn)椋簃ain方法中創(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沒(méi)有顯式提供,則編譯器會(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ì)象都可以正確銷毀
// main函數(shù)中并沒(méi)有直接調(diào)用Time類析構(gòu)函數(shù),而是顯式調(diào)用編譯器為Date類生成的默認(rèn)析構(gòu)函數(shù)
// 注意:創(chuàng)建哪個(gè)類的對(duì)象則調(diào)用該類的析構(gòu)函數(shù),銷毀那個(gè)類的對(duì)象則調(diào)用該類的析構(gòu)函數(shù)
到了這里,關(guān)于【C++】:類和對(duì)象(中)之類的默認(rèn)成員函數(shù)——構(gòu)造函數(shù)and析構(gòu)函數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!