用构造函数创建对象后,程序负责跟踪该对象,直到对象过期为止。对象过期时,程序将自动调用一个特殊的成员函数,该函数的名称——析构函数。析构函数完成清理工作,实际上还是很有用的。例如,用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()执行完毕后,才会调用析构函数。在窗口环境中,这意味着将在析构函数调用前关闭,导致无法看到信息。但是添加大括号后,析构函数调用将在到达返回语句前执行,从而显式相应信息。

C++ 类和对象 (5) 析构函数-LMLPHP

09-29 07:45