c++ Virtual关键字在类构造、析构函数使用与内存泄漏

1、virtual与构造、析构函数
  • 使用原则:类的构造函数不能是virtual函数,而类的析构函数可以且在类的继承中基类的析构函数通常必须为虚函数。
  • 基类的的析构函数不是虚函数的话,删除指针时,只有该类的内存被释放,派生类的没有,这样就内存泄漏了。
  • 原因分析:
    • 类的构造函数不能是虚函数:通俗地理解构造函数的作用就是为当前类创建对应的对象,如果为虚函数,则创建的不能为当前类创建对象,违背了构造函数的原则。
    • 类的析构函数可以是虚函数:理论上,由于类的析构函数为虚函数是合理的。而且,在继承层级的具体实现中,一般都是用父类的指针指向子类对象,那么如果基类的析构函数是虚函数,在delete 基类指针时,会调用子类的析构函数并释放该子类对象所占空间;而基类的析构函数不是虚函数,则并不会调用子类的析构函数,造成内存泄漏。下面为例子:
  • 代码实例:
#include<iostream>
using namespace std;
class ClxBase
{
public:
	ClxBase() {};
	virtual ~ClxBase() {};
	virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
}; class ClxDerived : public ClxBase
{
public:
	ClxDerived() {};
	~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; };
	void DoSomething() override{ cout << "Do something in class ClxDerived!" << endl; };
};


int main()
{
	ClxBase *pTest = new ClxDerived;
	pTest->DoSomething();
	delete pTest;

	system("pause");
	return 0;
}
  • 运行结果
    在这里插入图片描述
    而基类的析构函数不是虚函数运行结果如下,可见子类的析构函数并没用调用!
    在这里插入图片描述
  • 实例代码注意
    • 一般用new关键字创建的对象一定要使用delete关键字进行释放。注意new 时会调用构造函数对创建的对象进行初始化,delete时会调用析构函数进行释放对象前的清理工作。注意,析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作;同理构造函数也不是创建对象,而是对创建的对象进行一些初始化工作。
2、内存泄漏
  • 既然上面内容涉及到了内存泄漏的知识则在这里总结下c++内存泄漏的几种情况。
  • 1、没有匹配地使用new、delete。因为使用new则是在堆上创建的内存,需要用户手动释放。(延申:非new形式定义的对象在进程虚拟地址空间的栈地址上存储,new申请的空间在堆上创建。两种创建位置主要区别:1.空间大小 2、是否由系统自动回收3、创建速度)
  • 2、使用delete释放指向对象数组的指针时没有加[]。主要这里的对象指的时自定义的类对象,简单的基本数据类型对象不加[]也可以。其原因是如果没有方括号,那么这个指针就被默认为只指向一个对象,对象数组中的其他对象的析构函数就不会被调用,结果造成了内存泄露;而基本类型系统记忆其空间大小,无需调用构造函数。
  • 3、基类的析构函数不是虚函数。(当基类指针指向子类对象时,如果基类的析构函数不是virtual,那么子类的析构函数将不会被调用,子类的资源没有正确是释放,因此造成内存泄露)
  • 4、缺少拷贝构造函数。如果没有定义拷贝构造函数,那么编译器就会调用默认的拷贝构造函数,会逐个成员拷贝的方式来复制数据成员,如果是以逐个成员拷贝的方式来复制指针被定义为将一个变量的地址赋给另一个变量。这种隐式的指针复制结果就是两个对象拥有指向同一个动态分配的内存空间的指针。当释放第一个对象的时候,它的析构函数就会释放与该对象有关的动态分配的内存空间。而释放第二个对象的时候,它的析构函数会释放相同的内存,这样是错误的。
  • 5、缺少赋值构造函数。原理与拷贝构造函数相同。
  • 6、对象指针数组的释放与对象数组的释放不同。(数组中存放的是指向对象的指针,不仅要释放每个对象的空间,还要释放每个指针的空间,delete []p只是释放了每个指针,但是并没有释放对象的空间,正确的做法,是通过一个循环,将每个对象释放了,然后再把指针释放了。)
3、野指针出现情况
  • 1、定义指针没赋值NULL;
  • 2、指针越界访问
  • 3、delete ptr指针后,没有将NULL赋值给ptr。因为delete只是删除了ptr指向的内存空间,并不是删除了ptr指针。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值