1、析构函数
类的析构函数(Destructor)是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。删除对象时,自动被调用,用来释放对象占用的空间。析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~
)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
如果类是基类,并且可能会通过基类指针删除派生类对象,那么基类的析构函数应该是虚拟的。这样可以确保删除派生类对象时,正确地调用派生类的析构函数。
#include<iostream>
using namespace std;
class MyClass {
public:
MyClass() {
// 构造函数代码
}
~MyClass() {
// 析构函数代码,用于清理资源
}
};
int main() {
cout << "Hello, World!";
return 0;
}
2、C++ 创建对象三种方式
如在C++中定义了一个Test
类,有三种方式创建对象:
1)栈中分配内存
#include <iostream>
using namespace std;
class Test {
public:
int value;
Test(int val) : value(val) {
cout << "构造函数:为 "
<< value << " 分配内存(栈中)" << endl;
}
~Test() {
cout << "析构函数:销毁 "
<< value << " 对象(栈中)" << endl;
}
};
int main() {
Test p1(1); // 栈中分配内存
// p1 在作用域结束时,析构函数会被自动调用
return 0;
}
2)栈中分配内存,是上面创建的完整模式
#include <iostream>
using namespace std;
class Test {
public:
int value;
Test(int val) : value(val) {
cout << "构造函数:为 "
<< value << " 分配内存(栈中)" << endl;
}
~Test() {
cout << "析构函数:销毁 "
<< value << " 对象(栈中)" << endl;
}
};
int main() {
// 通过复制构造函数进行栈中分配
Test p2 = Test(2);
// p2 在作用域结束时,析构函数会被自动调用
return 0;
}
3)堆中分配内存
#include <iostream>
using namespace std;
class Test {
public:
int value;
Test(int val) : value(val) {
cout << "构造函数:为 "
<< value << " 分配内存(堆中)" << endl;
}
~Test() {
cout << "析构函数:销毁 "
<< value << " 对象(堆中)" << endl;
}
};
int main() {
Test* p3 = new Test(3); // 堆中分配内存
delete p3; // 手动调用析构函数,销毁堆内存
return 0;
}
注意:栈中分配内存,在栈中内存由系统自动的去分配和释放,而使用new创建的指针对象是在堆中分配内存,当不需要该对象时,需要我们手动的去释放,否则会造成内存泄漏。栈中对象的释放顺序,是后定义的先释放。
3、析构函数的使用示例
1)相同作用域
#include <iostream>
using namespace std;
class Test
{
int id;
public:
Test(int i)
{
id = i;
}
~Test()
{
cout<<"ID: "<<id
<<" destruction function is invoked!"
<<endl;
};
};
int main()
{
//栈中分配
Test t0(0);
//栈中分配,数组型对象
Test t1[3]{1,1,1};
Test *t2 = new Test(2); //堆中分配
delete t2;
Test *t3 = new Test[3]{3,3,3};//堆中分配
delete []t3;
cout<<"------End of Main-------"<<endl;
return 0;
}
2)不同作用域
#include <iostream>
using namespace std;
class Test
{
int id;
public:
Test(int i)
{
id = i;
}
~Test()
{
cout<<"ID: "<<id
<<" destruction function is invoked!"
<<endl;
};
};
//最先创建的对象,最后释放
Test t0(0);
void Func()
{
//创建静态对象,会在整个程序结束时自动释放
static Test t1(1);
//在Func结束时自动释放
Test t2(2);
cout<<"-----Func-----"<<endl;
}
int main()
{
Test t3(3);
//类型转换构造函数,这里会创建临时对象,
//将int型转成Test类型对象,
//在赋值结束后,临时变量销毁
t3 = 10;
cout<<"------Begin of Main-------"<<endl;
{
//花括号代表作用域,
//不需要等到main方法结束就释放了
Test t4(4);
}
Func(); 、//进入Func函数
cout<<"------End of Main-------"<<endl;
return 0;
}
3)动态内存管理
#include <iostream>
class MyClass {
private:
int* arr;
public:
MyClass(int size) {
arr = new int[size]; // 动态分配内存
std::cout <<
"构造函数:动态分配内存" << std::endl;
}
~MyClass() {
delete[] arr; // 释放动态分配的内存
std::cout <<
"析构函数:释放内存" << std::endl;
}
};
int main() {
MyClass obj(10); // 创建对象并分配内存
// 当 obj 离开作用域时,
//析构函数会被自动调用,释放内存
return 0;
}
4)虚析构函数
#include <iostream>
using namespace std;
class Base {
public:
Base() {
cout << "Base 类构造函数" << endl;
}
virtual ~Base() { // 虚析构函数
cout << "Base 类析构函数" << endl;
}
};
class Derived : public Base {
public:
Derived() {
cout << "Derived 类构造函数" << endl;
}
~Derived() override { // 重写析构函数
cout << "Derived 类析构函数" << endl;
}
};
int main() {
// 基类指针指向派生类对象
Base* basePtr = new Derived();
// 通过基类指针删除派生类对象,触发虚析构函数
delete basePtr;
return 0;
}
注意:通过基类指针删除派生类对象时,虚析构函数确保先调用派生类的析构函数,然后再调用基类的析构函数。若基类析构函数没有声明为 virtual
,则只会调用基类的析构函数,可能导致资源泄露。