0
点赞
收藏
分享

微信扫一扫

Cherno C++ P68 C++的虚析构函数

YouTube视频链接

C++的虚析构函数

本文是ChernoP68视频的学习笔记。
  如下代码,创建两个类一个叫base作为基类,创建一个公共构造函数并打印constructor,这样就知道类被构造了,也就是构造函数被调用了。然后写一个析构函数并打印destructor,Derived类做同样的事并且派生自Base类。
我们创建Base类和Derived类的一个实例并把它们分配到堆上。

#include<iostream>

class Base
{
public:
	Base() { std::cout << "Base Constructor\n"; }
	~Base() { std::cout << "Base Destructor\n"; }
};

class Derived : public Base
{
public:
	Derived() { std::cout << "Derived Constructor\n"; }
	~Derived() { std::cout << "Derived Destructor\n"; }
};

int main()
{
	Base* base = new Base();
	delete base;
	std::cout << "-----------------\n";
	Derived* derived = new Derived();
	delete derived;

	std::cin.get();
}

  按F5运行,我们发现当创建Base类的时候只会调用Base类的构造函数,删除它的时候也只会调用Base类的析构函数。而Derived类首先调用了基类Base的构造函数,然后是Derived类的构造函数 。当删除它的时候则是先调用Derived类的析构函数再调用Base类的析构函数。
在这里插入图片描述  若有一个多态类型poly,我们创建一个Derived实例,但把它赋值给Base类类型,把这种poly对象当作Base类指针来处理,但它实际上是一个指向Derived类型的指针。

int main()
{
	Base* base = new Base();
	delete base;
	std::cout << "-----------------\n";
	Derived* derived = new Derived();
	delete derived;
	std::cout << "-----------------\n";
	Base* poly = new Derived();
	delete poly;
	std::cin.get();
}

  按F5运行,发现基类构造函数和派生类构造函数都能被正确调用,然后当删除它的时候只有基类的析构函数被调用了,而派生类的析构函数没有被调用,这会导致内存泄漏。
在这里插入图片描述  当删除poly的时候,它不知道调用的析构函数可能有另一个析构函数,因为它没有被标记为虚函数。标记为virtual,意味着c++知道可能会有一个方法,在层次结构下的某种重写的方法。在普通的方法前面标记virtual,那么它就可以被覆写。而虚析构函数的意思不是覆写析构函数,而是加上一个析构函数。所以当把基类析构函数改为虚函数就会调用两个析构函数。它会先调用派生类析构函数,然后在层次结构中向上调用基类析构函数。
  为什么要调用派生类析构函数?若有一个成员int数组在堆上分配东西,在构造函数中分配,在析构函数中删除。运行当前代码发现没有调用那个派生析构函数,但是它调用了派生类的构造函数。我们在这里分配了20个字节的内存,然后永远不会调用第14行代码,因为析构函数没有被调用,永远不会删除堆分配数组,这就是所谓的内存泄漏。
  只需要将基类析构函数标记为虚函数就可以解决这个问题。意味着这个类可能被扩展为子类,可能会有一个析构函数也需要被调用。
在这里插入图片描述  我们发现派生类的析构函数首先被调用,然后调用基类的析构函数,这意味着数组得到了清理,即使当作多态类型来处理。

举报

相关推荐

0 条评论