类的四个默认成员函数->析构函数
3.析构函数
1.析构函数的概念
析构函数可以理解为反向的构造函数,他在对象生命期结束时,调用析构函数释放对象的内存空间。具体的析构函数在这几种情况下调用:
1.堆上的空间(使用new创建的对象)调用delete时
2.本地对象超出作用域
3.临时对象的销毁
4.显式的调用析构函数
2.析构函数注意事项
1.析构函数没有参数
2.析构函数不能重载
3.析构函数没有返回类型。
3.虚析构函数
虚析构函数是析构函数的重点,在出现继承时,构造函数不用考虑因为继承产生的问题,因为派生类的构造函数会自动调用基类的构造函数,析构函数与构造函数类似,派生类的析构函数也会自动调用。但是在继承体系中会出现一些问题。考虑这种情况。
class A { public: A(int _a=15):a(_a){} ~A() { cout << "~A()" << endl; } private: int a; }; class B :public A { public: B(int _a=15,int _b=10) : A(_a),b(_b){} ~B() { cout << "~B()" << endl; } private: int b; }; int main() { A *k = new B(11,22); delete k; return 0; }
测试结果:~A()
使用基类的指针指向派生类的对象时,调用delete k,会调用A的析构函数去释放内存,k虽然指向一个派生类的对象,但是k指针的类型是基类的,所以析构函数只能释放掉派生类中的基类部分,派生类自己特有的部分并没有被释放掉。这时,产生了内存泄漏。
这时我们引入虚函数这个概念。指向基类的指针在操作它的多态对象的虚函数时,会根据不同的对象操作对象自身的函数,当析构函数为虚函数时,编译器在执行析构函数时,会根据指针所指对象来决定调用那个函数,而不是根据指针类型来决定。
class A { public: A(int _a=15):a(_a){} virtual ~A() { cout << "~A()" << endl; } private: int a; }; class B :public A { public: B(int _a=15,int _b=10) : A(_a),b(_b){} ~B() { cout << "~B()" << endl; } private: int b; }; int main() { A *k = new B(11,22); delete k; return 0; }
测试结果:
~B()
~A()
执行派生类的析构函数。(打印两行是因为派生类的析构函数会自动调用基类的析构函数)。