1. 程式人生 > >具有子類的類,解構函式儘量定義為虛擬函式

具有子類的類,解構函式儘量定義為虛擬函式

由於本人才疏學淺,本文難免存在遺漏之處,歡迎大家留言指正,本人將感激不盡

一、使用new建立物件需要顯示的呼叫Delete來刪除物件,否則將造成記憶體洩漏。

程式碼如下所示

#include <iostream>
using namespace std;
class Test{
public:
	Test(int v = 0) : data(v){
		cout << "Test:" << v << endl;
	}
	~Test(){
		cout << "~Test:" << data << endl;
	}
	int data;
};

int main(){
	Test *p = new Test(1);
	Test t(2);
	return 0;
}

輸出結果如下所示:

Test:1
Test:2
~Test:2

可以看到通過new構造的物件沒有呼叫解構函式,造成記憶體洩漏;相反,通過Test t(2)構造的物件在程式結束時呼叫了解構函式。所以,我們平時要注意用delete 刪除通過new構造的物件。

二、類具有繼承關係時,虛擬函式應該定義為虛擬函式

假設存在父類Father,子類Son,以下兩條語句均合法:

Fathe * f = new Son; //(1)
Son * s = new Son;   //(2)

首先,我們要知道建立子類物件之前,會呼叫父類的建構函式,即除了子類物件之外,還會產生一個父類物件。

如果我們不將子類和父類的解構函式定義為虛擬函式時:
語句(1)將只調用父類的解構函式,而不會呼叫子類的解構函式,造成記憶體洩漏。
語句(2)正常,先呼叫子類的解構函式,接著呼叫父類的解構函式。

程式碼以及結果過如下:

#include <iostream>
using namespace std;
class Father{
public:
	Father(int v = 0) : data(v){
		cout << "Father:" << v << endl;
	}
	/*virtual*/ ~Father(){
		cout << "~Father:" << data << endl;
	}
	int data;
};
class Son : public Father{
public:
	Son(int v = 0) : Father(v), data(v){
		cout << "Son:" << v << endl;
	}
	/*virtual*/ ~Son(){
		cout << "~Son:" << data << endl;
	}
	int data;
};
int main(){
	Father *f = new Son(1);
	delete f;
	
	Son *s = new Son(2);
	delete s;

	return 0;
}

/*Father *f = new Son(1); */
Father:1
Son:1
~Father:1

/*Son *s = new Son(2);*/
Father:2
Son:2
~Son:2
~Father:2

可以看到,Father *f = new Son(2);構造的子類物件並沒有被釋放,造成記憶體洩漏。

接下來我們將子類和父類的解構函式都定義為虛擬函式,發現輸出結果如下:

Father:1
Son:1
~Son:1
~Father:1
Father:2
Son:2
~Son:2
~Father:2

此時可以看到,將父類和子類的解構函式設定為虛擬函式之後,將不再導致記憶體洩漏。

note:

1、若只將父類的解構函式定義為虛擬函式,也不會導致記憶體洩漏。
2、但是隻將子類的解構函式定義為虛擬函式,將導致core dumped,報錯如下,具體原因還未知,希望有大神讀到這篇文章時指點一下。

Father:1
Son:1
~Father:1
*** Error in `./test': free(): invalid pointer: 0x00000000017c9c28 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7fca6b4b57e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7fca6b4be37a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7fca6b4c253c]
./test[0x400b38]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7fca6b45e830]
./test[0x400a19]
======= Memory map: ========
00400000-00402000 r-xp 00000000 08:01 2501473                            /home/ross/Desktop/sword_offer/test/test
00601000-00602000 r--p 00001000 08:01 2501473                            /home/ross/Desktop/sword_offer/test/test
00602000-00603000 rw-p 00002000 08:01 2501473                            /home/ross/Desktop/sword_offer/test/test
017b8000-017ea000 rw-p 00000000 00:00 0                                  [heap]
7fca64000000-7fca64021000 rw-p 00000000 00:00 0 
7fca64021000-7fca68000000 ---p 00000000 00:00 0 
7fca6b135000-7fca6b23d000 r-xp 00000000 08:01 2626243                    /lib/x86_64-linux-gnu/libm-2.23.so
7fca6b23d000-7fca6b43c000 ---p 00108000 08:01 2626243                    /lib/x86_64-linux-gnu/libm-2.23.so
7fca6b43c000-7fca6b43d000 r--p 00107000 08:01 2626243                    /lib/x86_64-linux-gnu/libm-2.23.so
7fca6b43d000-7fca6b43e000 rw-p 00108000 08:01 2626243                    /lib/x86_64-linux-gnu/libm-2.23.so
7fca6b43e000-7fca6b5fe000 r-xp 00000000 08:01 2626173                    /lib/x86_64-linux-gnu/libc-2.23.so
7fca6b5fe000-7fca6b7fe000 ---p 001c0000 08:01 2626173                    /lib/x86_64-linux-gnu/libc-2.23.so
7fca6b7fe000-7fca6b802000 r--p 001c0000 08:01 2626173                    /lib/x86_64-linux-gnu/libc-2.23.so
7fca6b802000-7fca6b804000 rw-p 001c4000 08:01 2626173                    /lib/x86_64-linux-gnu/libc-2.23.so
7fca6b804000-7fca6b808000 rw-p 00000000 00:00 0 
7fca6b808000-7fca6b81e000 r-xp 00000000 08:01 2626211                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7fca6b81e000-7fca6ba1d000 ---p 00016000 08:01 2626211                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7fca6ba1d000-7fca6ba1e000 rw-p 00015000 08:01 2626211                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7fca6ba1e000-7fca6bb90000 r-xp 00000000 08:01 1575049                    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7fca6bb90000-7fca6bd90000 ---p 00172000 08:01 1575049                    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7fca6bd90000-7fca6bd9a000 r--p 00172000 08:01 1575049                    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7fca6bd9a000-7fca6bd9c000 rw-p 0017c000 08:01 1575049                    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7fca6bd9c000-7fca6bda0000 rw-p 00000000 00:00 0 
7fca6bda0000-7fca6bdc6000 r-xp 00000000 08:01 2626145                    /lib/x86_64-linux-gnu/ld-2.23.so
7fca6bf9a000-7fca6bfa0000 rw-p 00000000 00:00 0 
7fca6bfc4000-7fca6bfc5000 rw-p 00000000 00:00 0 
7fca6bfc5000-7fca6bfc6000 r--p 00025000 08:01 2626145                    /lib/x86_64-linux-gnu/ld-2.23.so
7fca6bfc6000-7fca6bfc7000 rw-p 00026000 08:01 2626145                    /lib/x86_64-linux-gnu/ld-2.23.so
7fca6bfc7000-7fca6bfc8000 rw-p 00000000 00:00 0 
7fff23521000-7fff23542000 rw-p 00000000 00:00 0                          [stack]
7fff23547000-7fff2354a000 r--p 00000000 00:00 0                          [vvar]
7fff2354a000-7fff2354c000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted (core dumped)

參考