C++類的構(gòu)造與析構(gòu)特點(diǎn)及作用詳解
一、類的構(gòu)造函數(shù)
什么是構(gòu)造函數(shù)
和類具有相同名稱,并且沒有返回值類型的函數(shù),就是類的構(gòu)造函數(shù)
概念模糊、直接舉例:
#include <stdio.h> #include <windows.h> struct Test { Test() // 和類具有相同的名、并且沒有返回值 { } }; int main() { return 0; }
構(gòu)造函數(shù)的特點(diǎn)
直接先來說特點(diǎn)吧,然后論證:
1、構(gòu)造函數(shù)在定義對象的時(shí)候被調(diào)用
2、構(gòu)造函數(shù)可以進(jìn)行函數(shù)重載,可以有很多個(gè)
3、創(chuàng)建對象時(shí)默認(rèn)調(diào)用的是無參構(gòu)造
證明1:
構(gòu)造函數(shù)在定義對象的時(shí)候被調(diào)用;
論證如下:
#include <stdio.h> struct Test { Test() { printf("你調(diào)用了構(gòu)造函數(shù)\n"); // 此處下斷點(diǎn)、如果該函數(shù)被調(diào)用肯定會停下來。 } }; int main() { Test te; printf("接力\n"); return 0; }
我們在Test()構(gòu)造的輸出語句上加斷點(diǎn)、當(dāng)程序調(diào)用Test的printf肯定會停下來,這個(gè)時(shí)候我們轉(zhuǎn)到反匯編,單步步過、直到函數(shù)返回之后,就能知到剛剛是在哪里調(diào)用的構(gòu)造函數(shù)了
vs2010:F7編譯、F5調(diào)試、ALT+8反匯編:
F10一直運(yùn)行到返回:
這里編譯器做了優(yōu)化,可以直接看出來是在Test定義對象的時(shí)候調(diào)用了構(gòu)造。
證明2:
構(gòu)造函數(shù)可以進(jìn)行函數(shù)重載,可以有很多個(gè);
論證如下:
#include <stdio.h> #include <Windows.h> struct Test { Test() { printf("你調(diào)用了構(gòu)造函數(shù)\n"); // 此處下斷點(diǎn)、如果該函數(shù)被調(diào)用肯定會停下來。 } Test(int a) { printf("重載%d\n",a); } Test(int a, int b) { printf("重載%d\n",a+b); } }; int main() { Test te; Test te1(1); Test te2(1,1); // 注意、調(diào)用有參的構(gòu)造函數(shù)時(shí),需要傳遞參數(shù) system("pause"); return 0; }
重載了兩個(gè),注意:調(diào)用有參數(shù)的構(gòu)造時(shí),需要傳遞參數(shù)。
運(yùn)行可以通過:
證明3:
創(chuàng)建對象時(shí)默認(rèn)調(diào)用的是無參構(gòu)造;
論證如下:
#include <stdio.h> #include <Windows.h> struct Test { Test(int a) { printf("重載%d\n",a); } Test(int a, int b) { printf("重載%d\n",a+b); } }; int main() { Test te; // 普通定義對象的方式、不帶參數(shù) system("pause"); return 0; }
首先我們刪除無參構(gòu)造,看看能否編譯通過:
不可以
然后刪除有參構(gòu)造:
#include <stdio.h> #include <Windows.h> struct Test { Test() { printf("你調(diào)用了構(gòu)造函數(shù)\n"); // 此處下斷點(diǎn)、如果該函數(shù)被調(diào)用肯定會停下來。 } }; int main() { Test te; system("pause"); return 0; }
可以
全部都加上:
#include <stdio.h> #include <Windows.h> struct Test { Test() { printf("你調(diào)用了構(gòu)造函數(shù)\n"); // 此處下斷點(diǎn)、如果該函數(shù)被調(diào)用肯定會停下來。 } Test(int a) { printf("重載%d\n",a); } Test(int a, int b) { printf("重載%d\n",a+b); } }; int main() { Test te; system("pause"); return 0; }
運(yùn)行結(jié)果:
這已經(jīng)證明了,Test te;平常這樣定義對象的時(shí)候,調(diào)用的是無參構(gòu)造。如果需要調(diào)用有參構(gòu)造,必須傳入?yún)?shù);
這個(gè)特點(diǎn)很簡單、有參函數(shù)肯定要傳參嘛,所以定義對象的時(shí)候肯定要傳入?yún)?shù)??;
但是這里建議無論什么時(shí)候?qū)戭?,最好還是寫上無參構(gòu)造,哪怕什么都不做也盡量寫上,避免不必要的麻煩。
構(gòu)造函數(shù)的作用
一般用于初始化類的成員
如下:
#include <stdio.h> #include <Windows.h> struct Test { int x; int y; int z; Test() { } Test(int x,int y,int z) // 構(gòu)造函數(shù)初始化對象 { this->x = x; this->y = y; this->z = z; } }; int main() { Test te; Test te1(1,2,3); // 定義對象并調(diào)用有參構(gòu)造進(jìn)行初始化 printf("%d %d %d\n",te1.x,te1.y,te1.z); // 輸出看看是否初始化成功 system("pause"); return 0; }
運(yùn)行如下:
初始化成功。
二、類的析構(gòu)函數(shù)
什么是析構(gòu)函數(shù)
類的構(gòu)造函數(shù)名前加上'~'這個(gè)符號,就是類的析構(gòu)函數(shù)
概念模糊、代碼如下:
#include <stdio.h> #include <Windows.h> struct Test { Test() { printf("你調(diào)用了一次類的構(gòu)造函數(shù)\n"); } ~Test() { printf("你調(diào)用了一次類的析構(gòu)函數(shù)\n"); } }; int main() { Test te; // system("pause"); // 這里就不要讓程序停下來了,不然析構(gòu)不了 return 0; }
~Test(){}就這個(gè)樣子
析構(gòu)函數(shù)的特點(diǎn)
依然直接先來說特點(diǎn),然后論證:
1、析構(gòu)函數(shù)不能重載、不能有參數(shù)
2、析構(gòu)函數(shù)在變量聲明周期結(jié)束時(shí)被調(diào)用
3、析構(gòu)函數(shù)被調(diào)用分兩種情況:堆棧中定義的對象、全局區(qū)中定義的對象
證明1:
析構(gòu)函數(shù)不能重載、不能有參數(shù);
編譯不通過。
既然不能有參數(shù),那重載更不可能了
證明成功。
證明2:
析構(gòu)函數(shù)在變量聲明周期結(jié)束時(shí)被調(diào)用;
局部變量的生命周期是在一個(gè)大括號內(nèi),即一個(gè)所處塊結(jié)束。
所以:
#include <stdio.h> #include <Windows.h> struct Test { Test() { printf("你調(diào)用了一次類的構(gòu)造函數(shù)\n"); } ~Test() { printf("你調(diào)用了一次類的析構(gòu)函數(shù)\n"); } }; int main() { { Test te; printf("te生命周期即將結(jié)束。\n"); } // 析構(gòu)應(yīng)該在這里被調(diào)用 printf("te生命周期結(jié)束。\n"); system("pause"); return 0; }
運(yùn)行結(jié)果如下:
斷點(diǎn)
結(jié)果
證明成功。
證明3:
析構(gòu)函數(shù)被調(diào)用分兩種情況:堆棧中定義的對象、全局區(qū)中定義的對象;
已知堆棧中定義的對象(局部變量)在塊語句結(jié)束之后就會被調(diào)用,那么帶有return的main函數(shù)是在返回前調(diào)用析構(gòu),還是返回后呢?
代碼如下:
#include <stdio.h> #include <Windows.h> struct Test { Test() { printf("你調(diào)用了一次類的構(gòu)造函數(shù)\n"); } ~Test() { printf("你調(diào)用了一次類的析構(gòu)函數(shù)\n"); // 斷點(diǎn)--匯編 } }; int main() { Test te; // system("pause"); // 不要使用pause,不然無法返回 return 0; }
斷點(diǎn)-調(diào)試-匯編:
可以看到是在函數(shù)返回前被調(diào)用的。
如果在全局區(qū)定義的對象呢?
這個(gè)問題很難說,像我一樣定義兩個(gè)斷點(diǎn)就行了,如下:
#include <stdio.h> #include <Windows.h> struct Test { Test() { printf("你調(diào)用了一次類的構(gòu)造函數(shù)\n"); } ~Test() // 斷點(diǎn) { printf("你調(diào)用了一次類的析構(gòu)函數(shù)\n"); } }; Test te; int main() { // system("pause"); // 不要使用pause,不然無法返回 return 0; // 斷點(diǎn) }
運(yùn)行:
發(fā)現(xiàn)一運(yùn)行就斷在了return,當(dāng)我們發(fā)F10繼續(xù)運(yùn)行的時(shí)候,并沒有直接調(diào)用析構(gòu),而是到了括號那里:
繼續(xù)F10:
通過翻譯,可以得知這就是進(jìn)程結(jié)束時(shí)的一些收尾工作。
繼續(xù)F10:
現(xiàn)在大概可以總結(jié)了,類的對象定義為全局變量時(shí),是在main函數(shù)結(jié)束之后進(jìn)程退出之前,調(diào)用的析構(gòu)函數(shù)。
小結(jié)
當(dāng)類的對象定義為局部變量時(shí)(堆棧),定義這個(gè)對象的塊作用域結(jié)束時(shí)就會調(diào)用該對象的析構(gòu)函數(shù),如果在main函數(shù)這個(gè)塊作用域中定義的對象,那么就是在return之前調(diào)用析構(gòu)。
當(dāng)類的對象定義為全局變量時(shí)(全局區(qū)),會在main函數(shù)return函數(shù)返回之后和進(jìn)程結(jié)束之前,調(diào)用該對象的析構(gòu)函數(shù)。
析構(gòu)函數(shù)的作用
我們知道了析構(gòu)函數(shù)都是在類的對象生命周期結(jié)束時(shí)被調(diào)用,那么就代表下面不會再使用到這個(gè)對象;所以析構(gòu)函數(shù)一般用于一些收尾的工作,以防忘記。
比如當(dāng)你使用了該對象的成員申請了內(nèi)存(malloc、new等)、或者open了一些文件,那么可以在析構(gòu)函數(shù)中free delete 或者close。
例如:
#include <stdio.h> #include <Windows.h> struct Test { int x; char* name; Test() { name = (char*)malloc(sizeof(char)*20); // 構(gòu)造時(shí)動(dòng)態(tài)申請 } ~Test() { if(this->name!=0) // 析構(gòu)時(shí)判斷是個(gè)否為空,不為空釋放 { free(name); name = 0; } } }; int main() { Test te; return 0; }
這里我就不運(yùn)行了,大家可以自己測試下。
總結(jié)
構(gòu)造函數(shù)
1、和類具有相同名稱,并且沒有返回值類型的函數(shù),就是類的構(gòu)造函數(shù)
2、構(gòu)造函數(shù)在定義對象的時(shí)候被調(diào)用
3、構(gòu)造函數(shù)可以進(jìn)行函數(shù)重載,可以有很多個(gè)
4、創(chuàng)建對象時(shí)默認(rèn)調(diào)用的是無參構(gòu)造
析構(gòu)函數(shù)
1、類的構(gòu)造函數(shù)名前加上'~'這個(gè)符號,就是類的析構(gòu)函數(shù)
2、析構(gòu)函數(shù)不能重載、不能有參數(shù)
3、析構(gòu)函數(shù)在變量聲明周期結(jié)束時(shí)被調(diào)用
4、析構(gòu)函數(shù)被調(diào)用分兩種情況:堆棧中定義的對象、全局區(qū)中定義的對象
到此這篇關(guān)于C++類的構(gòu)造與析構(gòu)特點(diǎn)及作用詳解的文章就介紹到這了,更多相關(guān)C++類的構(gòu)造與析構(gòu)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C++構(gòu)造析構(gòu)賦值運(yùn)算函數(shù)應(yīng)用詳解
- C++淺析構(gòu)造函數(shù)的特性
- C++類與對象深入之構(gòu)造函數(shù)與析構(gòu)函數(shù)詳解
- C++超詳細(xì)講解構(gòu)造函數(shù)與析構(gòu)函數(shù)的用法及實(shí)現(xiàn)
- C++分析類的對象作類成員調(diào)用構(gòu)造與析構(gòu)函數(shù)及靜態(tài)成員
- C++分析構(gòu)造函數(shù)與析造函數(shù)的特點(diǎn)梳理
- 一起來學(xué)習(xí)C++的構(gòu)造和析構(gòu)
- C++繼承中的對象構(gòu)造與析構(gòu)和賦值重載詳解
- C++編程析構(gòu)函數(shù)拷貝構(gòu)造函數(shù)使用示例詳解
相關(guān)文章
詳解c++ atomic原子編程中的Memory Order
在多核編程中,我們使用內(nèi)核對象【如:事件對象(Event)、互斥量對象(Mutex,或互斥體對象)、信號量對象(Semaphore)等】來避免多個(gè)線程修改同一個(gè)數(shù)據(jù)時(shí)產(chǎn)生的競爭條件。本文將詳細(xì)介紹c++ atomic原子編程中的Memory Order。2021-06-06