构造和析构函数

目前为止,我们不能像初始化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引用和指针用作函数形参一样。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值