C++之深入解析析构函数

文章讲述了C++中析构函数的调用时机,包括变量离开作用域、成员销毁、容器销毁、动态分配对象删除以及临时对象结束时。C++11引入了default关键字自动生成默认构造函数等,而delete用于禁止拷贝和赋值操作。文章还强调了析构函数在继承中的重要性,特别是虚析构函数,确保正确销毁多态对象。最后提到了纯虚析构函数的应用。
摘要由CSDN通过智能技术生成

一、调用析构函数时机

  • 无论何时一个对象被销毁,就会自动调用其析构函数:
    • 变量在离开其作用域时被销毁;
    • 当一个对象被销毁时,其成员被销毁;
    • 容器(无论是标准库容器还是数组)被销毁时,其元素被销毁;
    • 对于动态分配的对象,当对指向它的指针应用 delete 运算符时被销毁;
    • 对于临时对象,当创建它的完整表达式结束时被销毁。

二、使用 default

  • C++11 新标准中,如果需要默认的行为,那么可以通过在参数列表后面写上 =default 来要求编译器生成构造函数:
class Sales_data {
public:
	Sales_data() = default;
    Sales_data(const Sales_data&) = default;
    Sales_data& operator = (const Sales_data &);
    ~Sales_data() = default;
};

Sales_data& Sales_data::operator=(const Sales_data&) = default;

三、使用 delete

  • 大多类应该定义默认构造函数、拷贝构造函数和拷贝赋值运算符,无论是隐式地还是显式地,但对于某些类来说,这些操作没有合理的意义。在此情况下,定义类时必须采用某种机制阻止拷贝或赋值。例如,iostream 类阻止了拷贝,以避免多个对象写入或读取相同的 IO 缓冲。

① 使用 =delete 定义删除的函数

struct NoCopy {
    NoCopy() = default; 						  // 使用合成的默认构造函数
    NoCopy(const NoCopy&) = delete; 			  // 阻止拷贝
    NoCopy &operator = (const NoCopy&) = delete;  // 阻止赋值
    ~NoCopy() = default;
};

② 析构函数不能是删除的成员

  • 对于一个删除了析构函数的类型,编译器将不允许定义该类型的变量或创建该的临时对象(同理 Singleton 单例模式中的将析构函数私有化,如果将析构函数私有化后,将不允许在栈上创建类对象,但可以动态分配这种类型的对象),虽然不能定义这种类型的变量或成员,但可以动态分配这种类型的对象,但是不能释放这些对象:
#include <iostream>

using namespace std;

struct NoDtor{
    NoDtor() = default;
    ~NoDtor() = delete;
};

int main() {
    // NoDtor nd; // erorr,NoDtor的析构函数delete
    NoDtor *p = new NoDtor(); 
    // delete p; // error,NoDtor的析构函数delete
    return 0;
}

四、合成的拷贝控制成员可能是删除的

  • 如果一个类的数据成员不能默认构造、拷贝、复制或销毁,则对应的成员函数将被定义为删除的。同时如上所说,如果一个成员有删除的或不可访问的析构函数会导致合成的默认和拷贝构造函数被定义为删除的,其原因是如果没有这条规则,我们可能会创建出无法销毁的对象。

五、虚析构

  • 当用父类的指针来操作一个子类,在释放的时候,因为 delete 的父类指针,会造成子类申请的空间未释放,因此也需要用虚函数的原理应用于析构函数上。
  • 继承机制中,析构函数的调用顺序和构造函数相反,先释放子类再释放基类:
#include <iostream>
using std::cout;
using std::endl;

class Base {
public:
	Base(double base)
		: _base(new double(base)) {
		cout << "Base(double)" << endl;
	}

	virtual
		void print() const {
		cout << "*_base = " << *_base << endl;
	}

	// 一般情况下,只要基类中有一个虚函数,都要将析构函数设为虚函数
	virtual
		~Base()   // 析构函数只有一个
	{
		if (_base) {
			delete _base;
			cout << "~Base() " << endl;
		}
	}

private:
	double * _base;
};

class Derived
	: public Base {
public:
	Derived(double base, double derived)
		: Base(base)
		, _derived(new double(derived)) {
		cout << "Derived(double, double)" << endl;
	}

	// virtual 
	void print() const {
		Base::print();// 直接去方法区拿
		cout << "*_derived = " << *_derived << endl;
	}

	// virtual
	~Derived() {
		if (_derived) {
			delete _derived;
			cout << "~Derived() " << endl;
		}
	}
private:
	double * _derived;
};

int main(void) {
	Base * pbase = new Derived(11.11, 12.12);
	pbase->print();

	delete pbase;
	return 0;
}

六、纯虚析构

  • 和纯虚函数不同,因为在释放内存时基类实际上也释放了内存,所以在纯虚析构中必须类内声明,类外实现:
class Animal{
	virtual ~Animal() = 0;
};

Animal::~Animal() {
    cout << "~Animal()" << endl;
}
  • 同样,含纯虚析构函数的类也是抽象类,不能进行实例化对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

╰つ栺尖篴夢ゞ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值