注:21天学通C++ (第7 版)
9.4析构函数
与构造函数一样,析构函数也是一种特殊的函数。与构造函数不同的是,析构函数在对象销毁时自动被调用。
9.4.1 声明和实现析构函数
与构造函数一样,析构函数也看起来像一个与类同名的函数,但前面有一个波浪号(~)。因此,Human 类的析构函数的声明类似于下面这样:
class Human
{
~Human (); //declaration of a destructor
};
这个析构函数可类声明中实现,也可在类声明外实现。在类声明中实现(定义)析构函数的代码类似于下面这样:
class Human
{
public:
~Human()
{
// destructor code here
};
}
在类声明外定义析构函数的代码类似于下面这样:
class Human
{
public:
~Human (); //destructor declaration
};
//destruction defination (implementation)
Human::~Human()
{
//destructor code here
}
正如您看到的,析构函数的声明与构造函数稍有不同,那就是包括波浪号(~)。然而。析构函数的作用于构造函数完全相反。
9.4.2 何时及如何使用析构函数
每当对象不再作用域内或通过delete 被删除,进而被销毁时,都将掉用析构函数。这使得析构函数是重置变量以及释放动态分配的内存和资源的理想场所。
使用C风格char 缓冲区是,您必须自己管理内存分配等,因此本书始终建议不要使用它们,而使用std::string .std::string 等工具都是类,它们充分利用了析构函数和构造函数,还有将在第12章 介绍的运算符。程序清单 9.7 所示的类Mystring 在构造函数中为一个字符串分配内存,并在析构函数中释放它。
程序清单9.7 一个简单的类,它封装了一个C风格字符串并通过析构函数释放它
#include <iostream>
#include <string.h>
using namespace std;
class MyString
{
private :
char* Buffer;
public :
//Constructor
MyString ( const char* InititialInput)
{
if (InititialInput != NULL)
{
Buffer = new char [strlen(InititialInput) + 1];
strcpy(Buffer , InititialInput) ;
}
else
Buffer =NULL ;
}
//Destruction: clears the buffer allocated in constructor
~MyString()
{
cout << " Invoking destructor ,clearing up "<< endl ;
if (Buffer != NULL)
delete [] Buffer;
}
int GetLength()
{
return strlen(Buffer);
}
const char* GetString()
{
return Buffer;
}
};
//end of class MyString
int main()
{
MyString SayHello("Hello from string class ");
cout <<" String buffer in Mystrig is "<< SayHello.GetLength();
cout <<" characters long "<<endl ;
cout <<" Buffer contains :" <<SayHello.GetString() <<endl;
return 0;
}
输出:
String buffer in Mystrig is 23 characters long
Buffer contains : Hello from string class
Invoking destructor ,clearing up
分析:
这个类封装了一个C风格字符串(MyString::Buffer),让您使用字符串时无需分配和释放内存。我们最感兴趣的是MyString() 和 ~MyString (),这个构造函数构造MyString对象。它通过输入参数获取一个输入字符串;然后使用strlen确定输入字符串的长度,并为C风格字符串Buffer 分配内存;在使用strcpy将输入的字符串复制到新分配的内存中。
析构函数不能重载,每个类只能有一个析构函数。如果您忘了实现是析构函数,编译器将创建一个伪析构函数并调用它,伪析构函数不能释放动态分配的内存。