<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
和類具有相同名稱,並且沒有返回值型別的函數,就是類別建構函式
概念模糊、直接舉例:
#include <stdio.h> #include <windows.h> struct Test { Test() // 和類具有相同的名、並且沒有返回值 { } }; int main() { return 0; }
直接先來說特點吧,然後論證:
1、建構函式在定義物件的時候被呼叫
2、建構函式可以進行函數過載,可以有很多個
3、建立物件時預設呼叫的是無參構造
證明1:
建構函式在定義物件的時候被呼叫;
論證如下:
#include <stdio.h> struct Test { Test() { printf("你呼叫了建構函式n"); // 此處下斷點、如果該函數被呼叫肯定會停下來。 } }; int main() { Test te; printf("接力n"); return 0; }
我們在Test()構造的輸出語句上加斷點、當程式呼叫Test的printf肯定會停下來,這個時候我們轉到反組合,單步步過、直到函數返回之後,就能知到剛剛是在哪裡呼叫的建構函式了
vs2010:F7編譯、F5偵錯、ALT+8反組合:
F10一直執行到返回:
這裡編譯器做了優化,可以直接看出來是在Test定義物件的時候呼叫了構造。
證明2:
建構函式可以進行函數過載,可以有很多個;
論證如下:
#include <stdio.h> #include <Windows.h> struct Test { Test() { printf("你呼叫了建構函式n"); // 此處下斷點、如果該函數被呼叫肯定會停下來。 } Test(int a) { printf("過載%dn",a); } Test(int a, int b) { printf("過載%dn",a+b); } }; int main() { Test te; Test te1(1); Test te2(1,1); // 注意、呼叫有參的建構函式時,需要傳遞引數 system("pause"); return 0; }
過載了兩個,注意:呼叫有引數的構造時,需要傳遞引數。
執行可以通過:
證明3:
建立物件時預設呼叫的是無參構造;
論證如下:
#include <stdio.h> #include <Windows.h> struct Test { Test(int a) { printf("過載%dn",a); } Test(int a, int b) { printf("過載%dn",a+b); } }; int main() { Test te; // 普通定義物件的方式、不帶引數 system("pause"); return 0; }
首先我們刪除無參構造,看看能否編譯通過:
不可以
然後刪除有參構造:
#include <stdio.h> #include <Windows.h> struct Test { Test() { printf("你呼叫了建構函式n"); // 此處下斷點、如果該函數被呼叫肯定會停下來。 } }; int main() { Test te; system("pause"); return 0; }
可以
全部都加上:
#include <stdio.h> #include <Windows.h> struct Test { Test() { printf("你呼叫了建構函式n"); // 此處下斷點、如果該函數被呼叫肯定會停下來。 } Test(int a) { printf("過載%dn",a); } Test(int a, int b) { printf("過載%dn",a+b); } }; int main() { Test te; system("pause"); return 0; }
執行結果:
這已經證明了,Test te;平常這樣定義物件的時候,呼叫的是無參構造。如果需要呼叫有參構造,必須傳入引數;
這個特點很簡單、有參函數肯定要傳參嘛,所以定義物件的時候肯定要傳入引數啊;
但是這裡建議無論什麼時候寫類,最好還是寫上無參構造,哪怕什麼都不做也儘量寫上,避免不必要的麻煩。
一般用於初始化類的成員
如下:
#include <stdio.h> #include <Windows.h> struct Test { int x; int y; int z; Test() { } Test(int x,int y,int z) // 建構函式初始化物件 { this->x = x; this->y = y; this->z = z; } }; int main() { Test te; Test te1(1,2,3); // 定義物件並呼叫有參構造進行初始化 printf("%d %d %dn",te1.x,te1.y,te1.z); // 輸出看看是否初始化成功 system("pause"); return 0; }
執行如下:
初始化成功。
類別建構函式名前加上'~'這個符號,就是類的解構函式
概念模糊、程式碼如下:
#include <stdio.h> #include <Windows.h> struct Test { Test() { printf("你呼叫了一次類別建構函式n"); } ~Test() { printf("你呼叫了一次類的解構函式n"); } }; int main() { Test te; // system("pause"); // 這裡就不要讓程式停下來了,不然解構不了 return 0; }
~Test(){}就這個樣子
依然直接先來說特點,然後論證:
1、解構函式不能過載、不能有引數
2、解構函式在變數宣告週期結束時被呼叫
3、解構函式被呼叫分兩種情況:堆疊中定義的物件、全域性區中定義的物件
證明1:
解構函式不能過載、不能有引數;
編譯不通過。
既然不能有引數,那過載更不可能了
證明成功。
證明2:
解構函式在變數宣告週期結束時被呼叫;
區域性變數的生命週期是在一個大括號內,即一個所處塊結束。
所以:
#include <stdio.h> #include <Windows.h> struct Test { Test() { printf("你呼叫了一次類別建構函式n"); } ~Test() { printf("你呼叫了一次類的解構函式n"); } }; int main() { { Test te; printf("te生命週期即將結束。n"); } // 解構應該在這裡被呼叫 printf("te生命週期結束。n"); system("pause"); return 0; }
執行結果如下:
斷點
結果
證明成功。
證明3:
解構函式被呼叫分兩種情況:堆疊中定義的物件、全域性區中定義的物件;
已知堆疊中定義的物件(區域性變數)在塊語句結束之後就會被呼叫,那麼帶有return的main函數是在返回前呼叫解構,還是返回後呢?
程式碼如下:
#include <stdio.h> #include <Windows.h> struct Test { Test() { printf("你呼叫了一次類別建構函式n"); } ~Test() { printf("你呼叫了一次類的解構函式n"); // 斷點--組合 } }; int main() { Test te; // system("pause"); // 不要使用pause,不然無法返回 return 0; }
斷點-偵錯-組合:
可以看到是在函數返回前被呼叫的。
如果在全域性區定義的物件呢?
這個問題很難說,像我一樣定義兩個斷點就行了,如下:
#include <stdio.h> #include <Windows.h> struct Test { Test() { printf("你呼叫了一次類別建構函式n"); } ~Test() // 斷點 { printf("你呼叫了一次類的解構函式n"); } }; Test te; int main() { // system("pause"); // 不要使用pause,不然無法返回 return 0; // 斷點 }
執行:
發現一執行就斷在了return,當我們發F10繼續執行的時候,並沒有直接呼叫解構,而是到了括號那裡:
繼續F10:
通過翻譯,可以得知這就是程序結束時的一些收尾工作。
繼續F10:
現在大概可以總結了,類的物件定義為全域性變數時,是在main函數結束之後程序退出之前,呼叫的解構函式。
當類的物件定義為區域性變數時(堆疊),定義這個物件的塊作用域結束時就會呼叫該物件的解構函式,如果在main函數這個塊作用域中定義的物件,那麼就是在return之前呼叫解構。
當類的物件定義為全域性變數時(全域性區),會在main函數return函數返回之後和程序結束之前,呼叫該物件的解構函式。
我們知道了解構函式都是在類的物件生命週期結束時被呼叫,那麼就代表下面不會再使用到這個物件;所以解構函式一般用於一些收尾的工作,以防忘記。
比如當你使用了該物件的成員申請了記憶體(malloc、new等)、或者open了一些檔案,那麼可以在解構函式中free delete 或者close。
例如:
#include <stdio.h> #include <Windows.h> struct Test { int x; char* name; Test() { name = (char*)malloc(sizeof(char)*20); // 構造時動態申請 } ~Test() { if(this->name!=0) // 解構時判斷是個否為空,不為空釋放 { free(name); name = 0; } } }; int main() { Test te; return 0; }
這裡我就不執行了,大家可以自己測試下。
1、和類具有相同名稱,並且沒有返回值型別的函數,就是類別建構函式
2、建構函式在定義物件的時候被呼叫
3、建構函式可以進行函數過載,可以有很多個
4、建立物件時預設呼叫的是無參構造
1、類別建構函式名前加上'~'這個符號,就是類的解構函式
2、解構函式不能過載、不能有引數
3、解構函式在變數宣告週期結束時被呼叫
4、解構函式被呼叫分兩種情況:堆疊中定義的物件、全域性區中定義的物件
到此這篇關於C++類別的構造與解構特點及作用詳解的文章就介紹到這了,更多相關C++類別的構造與解構內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45