C++超詳細(xì)講解構(gòu)造函數(shù)與析構(gòu)函數(shù)的用法及實(shí)現(xiàn)
寫(xiě)在前面
上一節(jié)解決了類與對(duì)象封裝的問(wèn)題,這一節(jié)就是對(duì)象的初始化和清理的構(gòu)造函數(shù)與析構(gòu)函數(shù)的內(nèi)容了;對(duì)象的初始化和清理也是兩個(gè)非常重要的安全問(wèn)題:一個(gè)對(duì)象或者變量沒(méi)有初始狀態(tài),對(duì)其使用后果是未知,同樣的使用完一個(gè)對(duì)象或變量,沒(méi)有及時(shí)清理,也會(huì)造成一定的安全問(wèn)題;c++利用了構(gòu)造函數(shù)和析構(gòu)函數(shù)解決上述問(wèn)題,這兩個(gè)函數(shù)將會(huì)被編譯器自動(dòng)調(diào)用,完成對(duì)象初始化和清理工作。對(duì)象的初始化和清理工作是編譯器強(qiáng)制要我們做的事情,因此如果我們不提供構(gòu)造和析構(gòu),編譯器提供編譯器提供的構(gòu)造函數(shù)和析構(gòu)函數(shù)是空實(shí)現(xiàn)。下面開(kāi)始正文:
構(gòu)造函數(shù)和析構(gòu)函數(shù)
語(yǔ)法
構(gòu)造函數(shù)語(yǔ)法: 類名(){}
1、沒(méi)有返回值也不寫(xiě)void
2、函數(shù)名稱與類名相同
3、構(gòu)造函數(shù)可以有參數(shù),因此可以發(fā)生重載
4、程序在調(diào)用對(duì)象時(shí)會(huì)自動(dòng)調(diào)用,無(wú)需手動(dòng)調(diào)用且只會(huì)調(diào)用一次
析造函數(shù)語(yǔ)法: ~類名(){}
1、沒(méi)有返回值也不寫(xiě)void
2、函數(shù)名稱與類名相同,在名稱前加上符號(hào)~
3、構(gòu)造函數(shù)不可以有參數(shù),因此不可以發(fā)生重載
4、程序在對(duì)象銷(xiāo)毀前會(huì)自動(dòng)調(diào)用析構(gòu),無(wú)需手動(dòng)調(diào)用且只會(huì)調(diào)用一次
作用
構(gòu)造函數(shù) 主要作用于創(chuàng)建對(duì)象時(shí)為對(duì)象的成員屬性賦值,構(gòu)造函數(shù)由編譯器自動(dòng)調(diào)用,無(wú)須手動(dòng)調(diào)用
析構(gòu)函數(shù) 主要作用于對(duì)象銷(xiāo)毀前系統(tǒng)自動(dòng)調(diào)用,執(zhí)行一些清理工作
代碼實(shí)現(xiàn)
#include<iostream>
using namespace std;
class Person
{
public:
Person()
{
cout << "Person構(gòu)造函數(shù)的調(diào)用" << endl;
}
~Person()
{
cout << "~Person析構(gòu)函數(shù)的調(diào)用" << endl;
}
};
void test01()
{
Person p;//棧上的對(duì)象運(yùn)行完畢后,編譯器自動(dòng)釋放
}
int main()
{
test01();
}
test01中創(chuàng)建了Person類p,主函數(shù)只是調(diào)用了一下創(chuàng)建的Person類p,編譯器就自動(dòng)調(diào)用了類的構(gòu)造函數(shù)和析構(gòu)函數(shù),析構(gòu)函數(shù)是程序運(yùn)行完畢后,編譯器自動(dòng)清理內(nèi)存空間的時(shí)候調(diào)用的。
兩大分類方式
按參數(shù)分為 有參構(gòu)造 和 無(wú)參構(gòu)造
按類型分為 普通構(gòu)造 和 拷貝構(gòu)造
無(wú)參和有參構(gòu)造很好理解,就是有無(wú)參數(shù)的區(qū)別,這里講一下拷貝構(gòu)造函數(shù):
//拷貝構(gòu)造函數(shù)
Person(const Person &p) //格式: const 類名 引用(&)變量名
{
//講傳入的人身上的所有屬性,拷貝到我身上
age = p.age;
cout << "Person的拷貝構(gòu)造函數(shù)調(diào)用" << endl;
}Person()的括號(hào)中是const Person &p,這是拷貝構(gòu)造的函數(shù)格式,他需要傳入相同類的對(duì)象,會(huì)產(chǎn)生一個(gè)具有相同屬性的類,比如p1的年齡為20,經(jīng)過(guò)拷貝構(gòu)造p2的年齡也會(huì)是20,但是兩個(gè)類對(duì)象的地址并不相同,這個(gè)到后面會(huì)具體解釋
三種調(diào)用方式
class Person
{
public:
//構(gòu)造函數(shù)
Person()
{
cout << "Person的無(wú)參構(gòu)造函數(shù)調(diào)用" << endl;
}
Person(int a)
{
age = a;
cout << "Person的有參構(gòu)造函數(shù)調(diào)用" << endl;
}
//拷貝構(gòu)造函數(shù)
Person(const Person &p) //格式: const 類名 引用(&)變量名
{
//講傳入的人身上的所有屬性,拷貝到我身上
age = p.age;
cout << "Person的拷貝構(gòu)造函數(shù)調(diào)用" << endl;
}
~Person()
{
cout << "~Person的析構(gòu)函數(shù)調(diào)用" << endl;
}
int age;
};括號(hào)法
Person p;//默認(rèn)構(gòu)造函數(shù)調(diào)用 Person p2(10);//有參構(gòu)造函數(shù) Person p3(p2);//拷貝構(gòu)造函數(shù) cout << "p2 age=" << p2.age << endl; cout << "p3 age=" << p3.age << endl;
注意事項(xiàng):調(diào)用默認(rèn)構(gòu)造函數(shù)的時(shí)候,不要加();Person p1() 編譯器會(huì)認(rèn)為是函數(shù)的聲明,不認(rèn)為在創(chuàng)建對(duì)象,等同于 void func()
顯示法
Person p; Person p2=Person(10);//有參構(gòu)造函數(shù) Person p3=Person(p2);//拷貝構(gòu)造函數(shù) Person(100);//匿名對(duì)象,特點(diǎn):當(dāng)前執(zhí)行完畢后,系統(tǒng)會(huì)立即回收掉匿名對(duì)象 cout << "AAAAA" << endl;
注意事項(xiàng)2:拷貝構(gòu)造初始化匿名對(duì)象等同于去掉括號(hào),導(dǎo)致重定義,不要用拷貝構(gòu)造初始化匿名對(duì)象,如果利用匿名對(duì)象的話,會(huì)和Peron p2=Person(10),重復(fù),出現(xiàn)重定義錯(cuò)誤;也不要用拷貝構(gòu)造初始化匿名對(duì)象。
隱式轉(zhuǎn)換法
Person p2 = 10;// 有參構(gòu)造函數(shù) Person p3 = p2;// 拷貝構(gòu)造函數(shù)
這個(gè)方法不推薦使用,調(diào)用的很不明顯,建議使用前面兩個(gè)方法調(diào)用構(gòu)造函數(shù)。
正確調(diào)用拷貝構(gòu)造函數(shù)
class Person
{
public:
Person()
{
cout << "Person的無(wú)參構(gòu)造函數(shù)調(diào)用" << endl;
}
Person(int a)
{
m_age = a;
cout << "Person的有參構(gòu)造函數(shù)調(diào)用" << endl;
}
Person(const Person& p)
{
m_age = p.m_age;
cout << "Person的拷貝構(gòu)造函數(shù)調(diào)用" << endl;
}
~Person()
{
cout << "Person 的析構(gòu)函數(shù)調(diào)用" << endl;
}
int m_age;
};正常調(diào)用
void test01()
{
Person p1(20);
Person p2(p1);
cout << "p2的年齡為:" << p2.m_age << endl;
}主函數(shù)中直接調(diào)用test01,這時(shí)候會(huì)顯示 p2的年齡為20,并且打?。嚎截悩?gòu)造函數(shù)的調(diào)用。所以說(shuō),使用一個(gè)已經(jīng)創(chuàng)建完畢的對(duì)象來(lái)初始化一個(gè)新對(duì)象的時(shí)候會(huì)調(diào)用拷貝構(gòu)造函數(shù)
值傳遞的方式給函數(shù)參數(shù)傳值
void doWork(Person p)
{ }
void test02()
{
Person p;
doWork(p);
}大家可以猜一下,在主函數(shù)調(diào)用,會(huì)運(yùn)行出什么結(jié)果,答案是:無(wú)參構(gòu)造函數(shù)調(diào)用和拷貝構(gòu)造函數(shù)調(diào)用,最后是兩個(gè)析構(gòu)函數(shù)調(diào)用;淺析一下過(guò)程,調(diào)用test02時(shí)創(chuàng)建了對(duì)象P,所以自動(dòng)調(diào)用無(wú)參構(gòu)造函數(shù),當(dāng)運(yùn)行到doWork(p)時(shí),調(diào)用拷貝構(gòu)造函數(shù),隨后拷貝構(gòu)造函數(shù)被清理,調(diào)用析構(gòu)函數(shù),程序結(jié)束前,p被清理,再次調(diào)用析構(gòu)函數(shù),程序結(jié)束。

值傳遞方式返回局部對(duì)象
Person doWork2()
{
Person p1;
cout << (int)&p1<<" 1 " << endl;
return p1;//返回就拷貝構(gòu)造函數(shù),隨后釋放掉,調(diào)用析構(gòu)
}
void test03()
{
Person p = doWork2();//重新創(chuàng)建局部對(duì)象,并不是上面返回的對(duì)象p1
cout << (int)&p<<" 2 " << endl;
}這里doWork2返回值時(shí)Person類型,也就是說(shuō)return p1后會(huì)拷貝構(gòu)造其屬性給test03調(diào)用的p,但是p1和p2并不是同一個(gè)對(duì)象,我們可以輸出他們的地址來(lái)驗(yàn)證。

這里的調(diào)用順序是:Person P1 的無(wú)參構(gòu)造,隨后輸出p1地址,然后返回值的時(shí)候先調(diào)用拷貝構(gòu)造函數(shù),把值賦給p,隨后清理p1調(diào)用析構(gòu);然后回到test03中,輸出p的地址,程序結(jié)束前調(diào)用析構(gòu),程序結(jié)束。
構(gòu)造函數(shù)的調(diào)用規(guī)則
編譯器提供:
1、創(chuàng)建一個(gè)類,c++編譯器會(huì)給每個(gè)類都至少添加三個(gè)函數(shù)
- 默認(rèn)構(gòu)造(空實(shí)現(xiàn))
- 析構(gòu)函數(shù)(空實(shí)現(xiàn))
- 值拷貝構(gòu)造(值拷貝)
2、如果我們寫(xiě)了有參構(gòu)造,編譯器不再提供默認(rèn)構(gòu)造,但是提供值拷貝構(gòu)造
如果我們寫(xiě)了拷貝構(gòu)造函數(shù),編譯器不再提供其他普通構(gòu)造函數(shù)
void test01()
{
Person p1;
p1.m_age = 19;
Person p2(p1);//即使沒(méi)寫(xiě)拷貝構(gòu)造仍然能得到結(jié)果p2.m_age =19
cout << "p2的年齡為:" << p2.m_age << endl;
}也就是說(shuō),就算我們不寫(xiě)無(wú)參和拷貝構(gòu)造,調(diào)用test03也會(huì)得到值拷貝后的p2年齡,這是編譯器默認(rèn)提供的三個(gè)函數(shù)。但是如果寫(xiě)了有參構(gòu)造,Person p1這行代碼就會(huì)報(bào)錯(cuò),提示找不到默認(rèn)構(gòu)造函數(shù);同樣的如果自己寫(xiě)了拷貝構(gòu)造,Person p1也會(huì)顯示同樣的錯(cuò)誤。

總結(jié)
這篇博文講了一部分對(duì)象的初始化和清理的內(nèi)容,著重講了構(gòu)造函數(shù)的調(diào)用方法、規(guī)則,以及拷貝構(gòu)造函數(shù)的概念,調(diào)用方法和細(xì)節(jié)。下一篇直接準(zhǔn)備深淺拷貝的內(nèi)容和初始化列表,靜態(tài)成員等的問(wèn)題,徹底結(jié)束對(duì)象的初始化和清理內(nèi)容,期待下篇與你們見(jiàn)面!
到此這篇關(guān)于C++超詳細(xì)講解構(gòu)造函數(shù)與析構(gòu)函數(shù)的用法及實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C++構(gòu)造函數(shù)與析構(gòu)函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C++深入講解對(duì)象的銷(xiāo)毀之析構(gòu)函數(shù)
- C++中構(gòu)造函數(shù)與析構(gòu)函數(shù)的詳解及其作用介紹
- 詳解C++中虛析構(gòu)函數(shù)的作用及其原理分析
- 詳解C++ 編寫(xiě)String 的構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù)、析構(gòu)函數(shù)和賦值函數(shù)
- C++中構(gòu)造函數(shù)與析構(gòu)函數(shù)的調(diào)用順序詳解
- 淺談C++基類的析構(gòu)函數(shù)為虛函數(shù)
- C++類成員構(gòu)造函數(shù)和析構(gòu)函數(shù)順序示例詳細(xì)講解
- C++ 私有析構(gòu)函數(shù)的作用示例詳解
相關(guān)文章
C++如何在構(gòu)造函數(shù)和析構(gòu)函數(shù)中調(diào)用虛擬函數(shù)
這篇文章主要介紹了C++如何在構(gòu)造函數(shù)和析構(gòu)函數(shù)中調(diào)用虛擬函數(shù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
win10系統(tǒng)VS2019配置點(diǎn)云庫(kù)PCL1.12.1的詳細(xì)流程
這篇文章主要介紹了win10系統(tǒng)VS2019配置點(diǎn)云庫(kù)PCL1.12.1的教程與經(jīng)驗(yàn)總結(jié),本文記錄小白在配置過(guò)程中踩過(guò)的一些小坑,需要的朋友可以參考下2022-07-07
C++中如何調(diào)用C語(yǔ)言的代碼實(shí)現(xiàn)
這篇文章主要介紹了C++中如何調(diào)用C語(yǔ)言的代碼實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
輸入3個(gè)字符串,將它們按照字母由大到小排序(示例代碼)
我們可以用string方法定義字符串變量。以下是具體實(shí)現(xiàn)代碼。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2013-10-10

