具有子类的类,析构函数尽量定义为虚函数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/nice_wen/article/details/83241998

由于本人才疏学浅,本文难免存在遗漏之处,欢迎大家留言指正,本人将感激不尽

本文只是举例介绍如果析构函数不定义为虚函数将会造成的后果,具体原因可参考 https://blog.csdn.net/nice_wen/article/details/83278596

一、使用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)

参考

https://blog.csdn.net/xld_hung/article/details/76776497
https://blog.csdn.net/luoweifu/article/details/53780438

猜你喜欢

转载自blog.csdn.net/nice_wen/article/details/83241998