用构造函数创建对象后,程序负责跟踪该对象,直到对象过期为止。对象过期时,程序将自动调用一个特殊的成员函数,该函数的名称——析构函数。析构函数完成清理工作,实际上还是很有用的。例如,用new来分配一个构造函数,则析构函数将使用delete来释放这些内存。Stock的构造函数没有使用new,因此析构函数实际上没有需要它清除的工作。在此情况下,只需要让编译器生成一个什么都不做的隐式析构函数即可,Stock类第一版正是这样做的。
举例,为Stock类提供一个析构函数。
和构造函数一样,析构函数的名称也很特殊:在类名前加上~。因此,Stock类的析构函数为~Stock()。另外,和构造函数一样,析构函数也可以没有返回值和声明类型。与构造函数不同的是,析构函数没有参数,因此Stock析构函数的原型必须是:
~Stock();
由于Stock的析构函数不承担任何重要的工作,因此可以将它编写为不执行任何操作的函数:
Stock::~Stock()
{
}
但是,有时候为了能看出析构函数何时被调用,可以这样写代码:
Stock::~Stock()
{
cout << "ByeBye," << company <<"!"<<endl;
}
什么时候调用析构函数由编译器决定,通常不能再代码中显式地调用析构函数。如果
创建的是静态存储类对象,则其析构函数将在程序结束时自动被调用。
创建的是自动存储类对象,则其析构函数将在程序执行完代码块时自动被调用。
如果对象是通过new创建的,则它将驻留在栈内存或者自由存储区中,当使用delete来释放内存时,其析构函数将自动被调用。最后,程序可以创建临时对象来完成特定的操作,在这种情况下,程序将在结束对该对象使用时自动调用其析构函数。
由于在类对象过期时析构函数将自动被调用,因此必须有一个析构函数。如果程序员没有提供析构函数,编译器将隐式地声明一个默认析构函数,并在发现导致对象被删除的代码后,提供默认析构函数的定义。
改进Stock类
下面将对构造函数和析构函数加入到类和方法的定义中。
1.头文件stock20.h,将构造函数和析构函数的原型加入到原来的类声明中。使用#ifndef防止多重包含。
#ifndef __STOCK20_H__
#define __STOCK20_H__
#include <string>
class Stock
{
private:
std::string company;
long shares;
double share_val;
double total_val;
void set_tot(){total_val = shares * share_val;}
public:
Stock();
Stock(const std::string &co,long n,double pr);
~Stock();
void buy(long num,double price);
void sell(long num,double price);
void update(double price);
void show();
};
#endif
2.实现文件stock20.cpp使用了using声明和限定名称来访问头文件中的各种声明,将构造函数和析构函数的方法定义添加到以前的方法中。并且每次被调用时,都显式一条信息。
#include <iostream>
#include "stock20.h"
Stock::Stock()
{
std::cout<<"Default constructor called\n";
company = "no name";
shares = 0;
share_val = 0.0;
total_val = 0.0;
}
Stock::Stock(const std::string &co,long n,double pr)
{
std::cout<<"Constructor using"<<co<<"called\n";
company = co;
if(n<0)
{
std::cout<<"Constructor using "<<co<<"called\n"
<<company<<"shares set to 0.\n";
shares = 0;
}
else
shares = n;
share_val = pr;
set_tot();
}
Stock::~Stock()
{
std::cout<<"Bye,"<<company<<"!"<<std::endl;
}
void Stock::buy(long num,double price)
{
if(num<0)
{
std::cout<<"Numer of shares can't be negative,Transaction is aborted"
<<std::endl;
}
else
{
shares += num;
share_val = price;
set_tot();
}
}
void Stock::sell(long num,double price)
{
if(num<0)
{
std::cout<<"Numer of shares can't be negative,Transaction is aborted"
<<std::endl;
}
else if(num >shares)
{
std::cout<<"You can't sell more than you have!Trancsaction is aborted"
<<std::endl;
}
else
{
shares -= num;
share_val=price;
set_tot();
}
}
void Stock::update(double price)
{
share_val = price;
set_tot();
}
void Stock::show() const
{
std::cout<<"Company:"<<company<<std::endl;
std::cout<<"Shares:"<<shares<<std::endl;
std::cout<<"Share price"<<share_val<<std::endl;
std::cout<<"Total worth:"<<total_val<<std::endl;
}
3.客户文件,使用Stock类,显示了构造函数和析构函数。
#include <iostream>
#include "stock20.h"
int main()
{
{
using std::cout;
cout<<"Using constructors to create new objects\n";
Stock stcok1("NanoSmart",12,20.0);
stock1.show();
Stock stock2=stock("Boffo objects",2,2.0);
stock2.show();
cout<<"Assingning stock1 to stock2:\n";
stock2=stock1;
cout<<"Listing stock1 and stock2:\n";
stock1.show();
stock2.show();
cout<<"Using a constructor to reset an object\n";
stock1=Stock("Nifty Foods",10,50.0);
cout<<"Revised stock1:\n";
stock1.show();
cout<<"Done\n";
const Stock land = Stock("Klu proper",3,3.0);
land.show();
}
return 0;
}
指的注意的是,main()的开头和末尾多了一个大括号。诸如stock1和stock2等自动变量将在程序退出其定义所属代码块时消失。如果没有这些大括号,代码块将为整个main(),因此只有main()执行完毕后,才会调用析构函数。在窗口环境中,这意味着将在析构函数调用前关闭,导致无法看到信息。但是添加大括号后,析构函数调用将在到达返回语句前执行,从而显式相应信息。