網(wǎng)站首頁 編程語言 正文
寫在前面
上一節(jié)解決了類與對象封裝的問題,這一節(jié)就是對象的初始化和清理的構(gòu)造函數(shù)與析構(gòu)函數(shù)的內(nèi)容了;對象的初始化和清理也是兩個非常重要的安全問題:一個對象或者變量沒有初始狀態(tài),對其使用后果是未知,同樣的使用完一個對象或變量,沒有及時清理,也會造成一定的安全問題;c++利用了構(gòu)造函數(shù)和析構(gòu)函數(shù)解決上述問題,這兩個函數(shù)將會被編譯器自動調(diào)用,完成對象初始化和清理工作。對象的初始化和清理工作是編譯器強制要我們做的事情,因此如果我們不提供構(gòu)造和析構(gòu),編譯器提供編譯器提供的構(gòu)造函數(shù)和析構(gòu)函數(shù)是空實現(xiàn)。下面開始正文:
構(gòu)造函數(shù)和析構(gòu)函數(shù)
語法
構(gòu)造函數(shù)語法: 類名(){}
1、沒有返回值也不寫void
2、函數(shù)名稱與類名相同
3、構(gòu)造函數(shù)可以有參數(shù),因此可以發(fā)生重載
4、程序在調(diào)用對象時會自動調(diào)用,無需手動調(diào)用且只會調(diào)用一次
析造函數(shù)語法: ~類名(){}
1、沒有返回值也不寫void
2、函數(shù)名稱與類名相同,在名稱前加上符號~
3、構(gòu)造函數(shù)不可以有參數(shù),因此不可以發(fā)生重載
4、程序在對象銷毀前會自動調(diào)用析構(gòu),無需手動調(diào)用且只會調(diào)用一次
作用
構(gòu)造函數(shù) 主要作用于創(chuàng)建對象時為對象的成員屬性賦值,構(gòu)造函數(shù)由編譯器自動調(diào)用,無須手動調(diào)用
析構(gòu)函數(shù) 主要作用于對象銷毀前系統(tǒng)自動調(diào)用,執(zhí)行一些清理工作
代碼實現(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;//棧上的對象運行完畢后,編譯器自動釋放
}
int main()
{
test01();
}
test01中創(chuàng)建了Person類p,主函數(shù)只是調(diào)用了一下創(chuàng)建的Person類p,編譯器就自動調(diào)用了類的構(gòu)造函數(shù)和析構(gòu)函數(shù),析構(gòu)函數(shù)是程序運行完畢后,編譯器自動清理內(nèi)存空間的時候調(diào)用的。
兩大分類方式
按參數(shù)分為 有參構(gòu)造 和 無參構(gòu)造
按類型分為 普通構(gòu)造 和 拷貝構(gòu)造
無參和有參構(gòu)造很好理解,就是有無參數(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()的括號中是const Person &p,這是拷貝構(gòu)造的函數(shù)格式,他需要傳入相同類的對象,會產(chǎn)生一個具有相同屬性的類,比如p1的年齡為20,經(jīng)過拷貝構(gòu)造p2的年齡也會是20,但是兩個類對象的地址并不相同,這個到后面會具體解釋
三種調(diào)用方式
class Person
{
public:
//構(gòu)造函數(shù)
Person()
{
cout << "Person的無參構(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;
};
括號法
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;
注意事項:調(diào)用默認(rèn)構(gòu)造函數(shù)的時候,不要加();Person p1() 編譯器會認(rèn)為是函數(shù)的聲明,不認(rèn)為在創(chuàng)建對象,等同于 void func()
顯示法
Person p;
Person p2=Person(10);//有參構(gòu)造函數(shù)
Person p3=Person(p2);//拷貝構(gòu)造函數(shù)
Person(100);//匿名對象,特點:當(dāng)前執(zhí)行完畢后,系統(tǒng)會立即回收掉匿名對象
cout << "AAAAA" << endl;
注意事項2:拷貝構(gòu)造初始化匿名對象等同于去掉括號,導(dǎo)致重定義,不要用拷貝構(gòu)造初始化匿名對象,如果利用匿名對象的話,會和Peron p2=Person(10),重復(fù),出現(xiàn)重定義錯誤;也不要用拷貝構(gòu)造初始化匿名對象。
隱式轉(zhuǎn)換法
Person p2 = 10;// 有參構(gòu)造函數(shù)
Person p3 = p2;// 拷貝構(gòu)造函數(shù)
這個方法不推薦使用,調(diào)用的很不明顯,建議使用前面兩個方法調(diào)用構(gòu)造函數(shù)。
正確調(diào)用拷貝構(gòu)造函數(shù)
class Person
{
public:
Person()
{
cout << "Person的無參構(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,這時候會顯示 p2的年齡為20,并且打印:拷貝構(gòu)造函數(shù)的調(diào)用。所以說,使用一個已經(jīng)創(chuàng)建完畢的對象來初始化一個新對象的時候會調(diào)用拷貝構(gòu)造函數(shù)
值傳遞的方式給函數(shù)參數(shù)傳值
void doWork(Person p)
{ }
void test02()
{
Person p;
doWork(p);
}
大家可以猜一下,在主函數(shù)調(diào)用,會運行出什么結(jié)果,答案是:無參構(gòu)造函數(shù)調(diào)用和拷貝構(gòu)造函數(shù)調(diào)用,最后是兩個析構(gòu)函數(shù)調(diào)用;淺析一下過程,調(diào)用test02時創(chuàng)建了對象P,所以自動調(diào)用無參構(gòu)造函數(shù),當(dāng)運行到doWork(p)時,調(diào)用拷貝構(gòu)造函數(shù),隨后拷貝構(gòu)造函數(shù)被清理,調(diào)用析構(gòu)函數(shù),程序結(jié)束前,p被清理,再次調(diào)用析構(gòu)函數(shù),程序結(jié)束。
值傳遞方式返回局部對象
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)建局部對象,并不是上面返回的對象p1
cout << (int)&p<<" 2 " << endl;
}
這里doWork2返回值時Person類型,也就是說return p1后會拷貝構(gòu)造其屬性給test03調(diào)用的p,但是p1和p2并不是同一個對象,我們可以輸出他們的地址來驗證。
這里的調(diào)用順序是:Person P1 的無參構(gòu)造,隨后輸出p1地址,然后返回值的時候先調(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)建一個類,c++編譯器會給每個類都至少添加三個函數(shù)
- 默認(rèn)構(gòu)造(空實現(xiàn))
- 析構(gòu)函數(shù)(空實現(xiàn))
- 值拷貝構(gòu)造(值拷貝)
2、如果我們寫了有參構(gòu)造,編譯器不再提供默認(rèn)構(gòu)造,但是提供值拷貝構(gòu)造
如果我們寫了拷貝構(gòu)造函數(shù),編譯器不再提供其他普通構(gòu)造函數(shù)
void test01()
{
Person p1;
p1.m_age = 19;
Person p2(p1);//即使沒寫拷貝構(gòu)造仍然能得到結(jié)果p2.m_age =19
cout << "p2的年齡為:" << p2.m_age << endl;
}
也就是說,就算我們不寫無參和拷貝構(gòu)造,調(diào)用test03也會得到值拷貝后的p2年齡,這是編譯器默認(rèn)提供的三個函數(shù)。但是如果寫了有參構(gòu)造,Person p1這行代碼就會報錯,提示找不到默認(rèn)構(gòu)造函數(shù);同樣的如果自己寫了拷貝構(gòu)造,Person p1也會顯示同樣的錯誤。
總結(jié)
這篇博文講了一部分對象的初始化和清理的內(nèi)容,著重講了構(gòu)造函數(shù)的調(diào)用方法、規(guī)則,以及拷貝構(gòu)造函數(shù)的概念,調(diào)用方法和細(xì)節(jié)。下一篇直接準(zhǔn)備深淺拷貝的內(nèi)容和初始化列表,靜態(tài)成員等的問題,徹底結(jié)束對象的初始化和清理內(nèi)容,期待下篇與你們見面!
原文鏈接:https://blog.csdn.net/m0_58618795/article/details/124903817
相關(guān)推薦
- 2023-07-18 List集合循環(huán)刪除特殊元素之六種方法(實踐)
- 2022-03-15 PEM_read_bio_X509_AUX() failed (SSL: error:0906D06
- 2022-10-01 Python利用Bokeh進行數(shù)據(jù)可視化的教程分享_python
- 2023-04-02 Python中的常見數(shù)據(jù)集打亂方法_python
- 2023-07-04 Spring AOP講解及實例
- 2021-12-07 C語言SetConsoleTextAttribute函數(shù)使用方法_C 語言
- 2023-07-05 React 簡單實現(xiàn) v-if和v-show的元素控制效果
- 2022-09-12 python中的集合及集合常用的使用方法_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支