C++学习笔记50——继承中的析构函数

1,派生类的析构函数

派生类的析构函数不负责撤销基类对象的成员,编译器总是显式调用派生类对象基类部分的析构函数。
这句话的含义是:我们定义派生类的析构函数时,不用管基类部分的成员,只撤销派生类自己的成员即可(如果需要的话)。编译器会自己调用基类的析构函数。我们不用在派生类的析构函数中显示调用它。

另:不管我们定不定义自己的析构函数,编译器都会合成默认的版本;这一点与构造函数不同。
例子:
class Base4
{
public:
	Base4(int ii, int jj) :i(ii), j(jj) { cout << "调用基类的一般构造函数" << endl; }//基类的一般构造函数
	Base4() :i(0), j(5203132) { cout << "调用基类的默认构造函数" << endl; }//基类的默认构造函数
	~Base4() { cout << "调用基类的析构函数" << endl; }
	void show_base() { cout << i << "\t" << j<<"\t"; }
public:
	int i;
private:
	int j;
};

class D4 :public Base4
{
public:
	D4() :k(0) { cout << "调用派生类的默认构造函数" << endl; }//派生类的默认构造函数
	D4(int ii, int jj, int kk) :Base4(ii, jj), k(kk) { }//派生类的一般构造函数
	D4(int kk) : k(kk) {}//派生类的一般构造函数,隐式调用基类的默认构造函数
	~D4() { cout << "调用派生类的析构函数" << endl; }

	int k;
	void show_d() { show_base(); cout << k << endl; }
};

//主函数
int main()
{
	/*******************************************************************/
	//  派生类的析构函数
	/*******************************************************************/
	cout << "D4 *pD4 = new D4:" << endl;
	D4 *pD4 = new D4;

	cout << "\ndelete pD4:" << endl;
	delete pD4;

	system("pause");
	return 0;
}

执行结果:


从上面我们看到,当我们delete pD4的时候,先调用了派生类的析构函数,然后又自动调用了基类的析构函数。


2,虚析构函数

处理继承层次中的对象时,指针的静态类型可能与被删除对象的动态类型不同,可能会删除实际指向派生类对象的基类类型指针,此种行为是未定义的。
类型定义不变,修改主函数为如下所示:
//主函数
int main()
{
	/*******************************************************************/
	//  派生类的析构函数
	/*******************************************************************/
	Base4 *pB4 = new D4;
	delete pB4;

	system("pause");
	return 0;
}

一个指向基类的指针,实际指向了一个派生类,如此调用delete结果会如何呢?


很明显,只有基类的析构函数被调用,派生类的析构函数喂被调用。如果派生类中新增了动态分配的成员,则这部分成员的内存未被释放,发生内存泄露。
但是,基类指针指向派生类对象的情况又是经常遇到,不可避免的。所以应该怎样处理这种情况?
答案就是在基类中定义virtual 析构函数。
我们将基类定义中的析构函数改为virtual析构函数,其他不变:
class Base4
{
public:
	Base4(int ii, int jj) :i(ii), j(jj) { cout << "调用基类的一般构造函数" << endl; }//基类的一般构造函数
	Base4() :i(0), j(5203132) { cout << "调用基类的默认构造函数" << endl; }//基类的默认构造函数
	virtual ~Base4() { cout << "调用基类的析构函数" << endl; }//虚析构函数
	void show_base() { cout << i << "\t" << j<<"\t"; }
public:
	int i;
private:
	int j;
};

同样使用上一个例子中的主函数,执行结果如下:


显然,派生类和基类的析构函数都被调用了,不会有内存泄漏发生。


3,其他注意项

  1. 如果继承层次中根类的析构函数为虚函数,则派生类析构函数也是虚函数,不论是自己定义的还是合成的;
  2. 复制控制成员3法则:如果类需要析构函数,则它也需要赋值操作符和复制构造函数。
  3. 但是,基类的虚析构函数是三法则的一个重要例外:基类几乎总是需要虚析构函数,但并不一定需要赋值操作符和复制构造函数。
  4. 构造函数和赋值操作符不是虚函数。
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值