欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

构造和析构函数

程序员文章站 2022-03-11 18:00:35
...

目前为止,我们不能像初始化int,double类型那样初始化类,比如,

int year=1001;  //合法的声明
Stock hot={"Auto",200,50.25}; //非法的声明

主要原因是类Stock的数据成员是私有的,只能通过成员函数来访问,因此需要设计合适的成员函数来初始化Stock类。

构造函数

c++提供了一个特殊的成员函数—构造函数,专门用于构造新对象,将值赋给它的数据成员。意思是,c++为这些成员函数提供了名称和语法,而程序员只需要提供方法定义。构造函数的名称与类名相同,例如,构造一个Stock类,它的构造函数可能是名为Stock( )的成员函数。

1.声明和定义构造函数

拿Stock类来举例,创建它的构造函数,声明如下

Stock(const string& co , long n=0, double pr=0.0);

注意:没有返回类型,原型位于类声明的公共部分。

下面是构造函数的一种可能定义:

Stock::Stock(const string& co , long n=0, double pr=0.0)
{
    company=co;
    if (n<0)
    {
        std::cout<<"Number of shares can't be nagative: "<<company<<" shares set 0 .\n";
        shares=0;
    }
    else
    {
        shares=n;
    }
    share_val=pr;
    set_tot();
}

此处的构造函数与上文的acquire()函数功能类似,但是有本质的区别,区别在于程序声明对象时,将自动调用构造函数

2. 成员名和参数名

如果不熟悉构造函数,可能会将构造函数的参数名选择为成员名,这会造成混乱。参数名不能用类成员相同
为了避免这种混乱,一种常见的做法是:

  • 在数据成员名中使用m_前缀;
class Stock
{
private:
    std::string m_company;//string类位于名称空间std中
    long m_shares;//股票数量
    double m_share_val;//每股价格
    double m_total_val;//股票总价值
    void set_tot(){m_total_val=m_share_val*m_shares;}
....
}
  • 在数据成员中使用后缀_;
class Stock
{
private:
    std::string company_;//string类位于名称空间std中
    long shares_;//股票数量
    double share_val_;//每股价格
    double total_val_;//股票总价值
    void set_tot(){total_val=share_val_*shares_;}
....
}

3.使用构造函数

c++提供了两种使用构造函数来初始化对象的方式。

  • 第一种方式:显示地调用构造函数
Stock food=Stock("hello world",200,34.5);
  • 第二种方式:隐式的调用构造函数
Stock food("hello world",200,34.5);
  • 构造函数与new一起使用的方法
Stock* pf=new Stock("hello world",200,34.5);

4. 默认构造函数

默认构造函数是在未提供显示初始值时,用来创建对象的构造函数。即用于下面这种声明的构造函数:

Stock fluffy_the_cat;

注意:只有程序中没有提供任何构造函数时,c++编译器才会提供默认构造函数,默认构造函数没有参数,声明中不包括值。为类定义了构造函数后,程序员就必须为它提供默认构造函数,如果提供了非默认构造函数,而没有提供默认构造函数,那么 Stock fluffy_the_cat 的声明将会出错。

  • 创建默认构造函数的方式之一:给已有构造函数的所有参数提供默认值;
Stock::Stock(const string& co="Error" , long n=0, double pr=0.0);
  • 另一种方式是通过函数重载来定义另一个构造函数—一个没有参数的构造函数;
Stock();

注意:由于只能有一个默认构造函数,因此上述两种方式只能任选其一

析构函数

用构造函数创建对象后,程序会跟踪该对象,直到其过期为止。对象过期时,程序将自动调用一个特殊的成员函数—-析构函数。析构函数完成清理工作,比如使用new分配的动态内存,析构函数将使用delete来释放内存,如果构造函数没有使用new,那么实际上析构函数没有什么需要完成的任务。

  • 创建析构函数:析构函数的名称很特殊,在类名前加上~,没有返回值和声明类型。
~Stock();
  • 定义析构函数:
Stock::~Stock()
{

}

如果程序没有提供析构函数,编译器将隐式的声明一个析构函数,并在对象删除时,提供默认析构函数的定义。

下面是对前文的Stock类的改进:

.h文件

#ifndef STOCK00_H_
#define STOCK00_H_

#include <string>//string类头文件

class Stock
{
private:
    std::string m_company;//string类位于名称空间std中
    long m_shares;//股票数量
    double m_share_val;//每股价格
    double m_total_val;//股票总价值
    void set_tot(){m_total_val=m_share_val*m_shares;}
public:
    //默认构造函数
    Stock();
    //非默认构造函数
    Stock(const std::string& company,long shares,double shares_val);
    //析构函数
    ~Stock();

    //void acquire(const std::string& com,long n,double pr);
    void buy(long num , double price);
    void sell(long num , double price);
    void update(double price);
    void show()const;
};


#endif

.c文件

#include <iostream>
#include "Stock00.h"
//默认构造函数
Stock::Stock()
{
    m_company="Error";
    m_shares=0;
    m_share_val=0.0;
}

//非默认构造函数
Stock::Stock(const std::string& company,long shares,double shares_val)
{
    m_company=company;
        if (shares<0)
        {
            std::cout<<"Number of shares can't be nagative: "<<m_company<<" shares set 0 .\n";
            m_shares=0;
        }
        else
        {
            m_shares=shares;
        }
        m_share_val=shares_val;
        set_tot();
}
//析构函数
Stock::~Stock()
{
    std::cout<<"调用析构函数 \n";
}
////获取股票
//void Stock::acquire(const std::string& com,long n,double pr)
//{
//  m_company=com;
//  if (n<0)
//  {
//      std::cout<<"Number of shares can't be nagative: "<<m_company<<" shares set 0 .\n";
//      m_shares=0;
//  }
//  else
//  {
//      m_shares=n;
//  }
//  m_share_val=pr;
//  set_tot();
//}
//增持股票
void Stock::buy(long num , double price)
{
    if (num<0)
    {
        std::cout<<"Number of shares purchased can't be nagative . "<<"\n";
    } 
    else
    {
        m_shares +=num;
        m_share_val=price;
        set_tot();
    }


}
//卖出股票
void Stock::sell(long num , double price)
{
    if (num<0)
    {
        std::cout<<"Number of shares sold can't be nagative .\n";
    } 
    else
        if(num>m_shares)
        {
            std::cout<<" You can't sell more than you have !\n";
        }
        else
        {
            m_shares -=num;
            m_share_val=price;
            set_tot();
        }

}
//更新股票价格
void Stock::update(double price)
{
    m_share_val=price;
    set_tot();
}
//显示股票信息
void Stock::show()const
{
    std::cout<<" company: "<<m_company
        <<" shares: "<<m_shares
        <<" shares price: $ "<<m_share_val
        <<" total price: $ "<<m_total_val<<std::endl;
}

main.cpp

#include <iostream>
#include "Stock00.h"

int main()
{
    Stock flutty_the_cat;
    const Stock flutty_the_cat2=Stock("hhhh",200,23.4);
    flutty_the_cat2.show();
    flutty_the_cat.show();
    flutty_the_cat.buy(13,18.215);
    flutty_the_cat.show();
    flutty_the_cat.sell(400,20.00);
    flutty_the_cat.show();
    flutty_the_cat.buy(300000,40.125);
    flutty_the_cat.show();
    flutty_the_cat.sell(300000,0.125);
    flutty_the_cat.show();

    return 0;
}

运行结果:
构造和析构函数

程序需要注意的几点:

  1. 在c++11中可以将列表初始化用于类,只要提供与某个构造函数匹配的参数列表的内容,并用大括号将他们括起来即可:
Stock flutty_the_cat2={"hhhh",200,23.4};
  1. const成员函数
    在上例中,void Stock::show()const ,将 const 关键字放在函数的括号后面。当类方法不修改调用对象,就应将其声明为const。就像应该尽可能使用const引用和指针用作函数形参一样。
相关标签: