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
,则只会调用基类的析构函数,可能导致资源泄露。