C++ 遗失的子类析构函数

这篇博文所讲的是多态中的一个小BUG

我们知道,在构造函数中调用了new给指针分配内存,那么就要在析构函数中释放掉该内存;那么,如果在多态实验中 基类指针指向子类对象时会怎么样呢?

代码:

#include <iostream>
#include <string.h>

class Father {
public:
	Father(const char *addr = "中国") {
		std::cout << "调用了Father类的构造函数" << std::endl;
		this->addr = new char[strlen(addr)+1];
		strcpy_s(this->addr, strlen(addr)+1, addr);
	}

	~Father() {
		std::cout << "调用了Fahter类的析构函数" << std::endl;
		if (addr) {
			delete addr;
			addr = NULL;
		}
	}

private:
	char *addr;
};

class Son : public Father {
public:
	Son(const char *game = "吃鸡", const char *addr = "中国") : Father(addr) {
		std::cout << "调用了Son类的构造函数" << std::endl;
		this->game = new char[strlen(game)+1];
		strcpy_s(this->game, strlen(game)+1, game);
	}

	~Son() {
		std::cout << "调用了Son类的析构函数" << std::endl;
		if (game) {
			delete game;
			game = NULL;
		}
	}

private:
	char *game;
};
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200217105951386.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NwcF9sZWFybmVy,size_16,color_FFFFFF,t_70)
int main(void) {
	std::cout << "---示例一---" << std::endl;
	Father *father = new Father();
	delete father;

	std::cout << "---示例二---" << std::endl;
	Son *son = new Son();
	delete son;

	std::cout << "---示例三---" << std::endl;
	father = new Son();
	delete father;

	system("pause");
	return 0;
}

运行截图:

在这里插入图片描述

在示例三中,竟然没有调用Son类的析构函数来释放内存,为什么会这样呢?

解决方案:

在基类的析构函数前加上 virtual 关键字

// 把Father类的析构函数定义为virtual函数时,
// 如果对 Father类的指针使用delete操作时,
// 就会对该指针使用“动态析构”:
// 如果这个指针,指向的是子类对象,
// 那么会先调用该子类的析构函数,再调用自己类的析构函数

virtual ~Father() {
		std::cout << "调用了Fahter类的析构函数" << std::endl;
		if (addr) {
			delete addr;
			addr = NULL;
		}
	}

运行截图:

在这里插入图片描述

【注意】
为了防止内存泄露,最好是在基类析构函数上添加virtual关键字,使基类析构函数为虚函数
目的在于,当使用delete释放基类指针时,会实现动态的析构:
1.如果基类指针指向的是基类对象,那么只调用基类的析构函数;
2.如果基类指针指向的是子类对象,那么先调用子类的析构函数,再调用父类的析构函数。


可别小看那一点点的内存就不要释放掉,积累成多,这个道理应该要懂得!

发布了39 篇原创文章 · 获赞 17 · 访问量 3829

猜你喜欢

转载自blog.csdn.net/cpp_learner/article/details/104354505