C++学习:类

一、类的概念

类是一种将抽象转换为用户定义类型的C++工具,它将数据和数据处理组合成一个整体。

比如股票类,首先要考虑如何表示股票。可以将某人持有的股票当成一个基本单元,数据包括他持有股票的数量,哪个公司的股票,还有最初购买的价格和购买的时间,股票的处理有增持,卖出,更新价格等。

类一般由类声明和类方法定义两部分组成,

类声明:以数据成员的方式描述部分,以成员函数的方式描述公有接口;

类方法定义:描述如何实现类成员函数。

可以这么说,类声明就是画个饼,类方法就是去实现这个饼。

二、类的声明

一般将类声明放在头文件中,就是.h文件,将类的实现放在源文件中,就是.cpp文件。

下面是stock类的类声明

#ifndef STOCK_H
#define STOCK_H
#include 

using namespace std;

class stock
{
private:
    string company; //股票发行的公司
    long shares; //持有股票数量
    double share_val; //每股的价格
    double total_val; //持股的总金额
    void set_tot() {total_val = shares * share_val;}
    
public:
    void acquire(const string& co, long n, double pr);
    void buy(long num, double price);
    void sell(long num, double price);
    void update(double price);
    void show();
};

#endif // STOCK_H

stock是这个类的类型名,我们可以声明stock类型的变量,也称为对象或实例,每个对象都表示一支股票,可以通过下面的声明创建两个stock对象

stock wang; 
stock li; 

 private和public关键字是C++中新出现的,它们用来描述对类成员的访问权限。private表示类的私有部分,public表示类的公有部分。使用类对象的程序可以直接访问类的公有部分;但类的私有部分只能通过类的成员函数来访问。

三、实现类的成员函数

类成员函数的定义与常规函数的定义非常类似,有函数头、函数体,也可以有返回类型和参数。区别在于,定义类的成员函数需要使用类的作用域解析运算符::来标示函数所属的类,类的成员函数可以访问类的私有成员数据。

void stock::update(double price)

 这表示update()函数是stock类的成员函数。

类的成员函数,也就是类的实现代码如下

#include "stock.h"
#include 

using namespace std;

//acquire()函数管理对某个公司股票首次购买,公司名称,购买数量,每股单价
void stock::acquire(const string& co, long n, double pr)
{
    company = co;
    if(n<0)
    {
        cout << "number of shares can't be nagative; ";
        cout << company << " shares set to 0.\n";
        shares = 0;
    }
    else
    {
        shares = n;
    }
    
    share_val = pr;
    set_tot();
}

//增持股票,增持的数量,和当时的价格
void stock::buy(long num, double price)
{
    if(num < 0)
    {
        cout << "number of shares purchased can't be nagative; ";
        cout <<  " Transaction is aborted.\n";
    }
    else
    {
        shares += num;
        share_val = price;
        set_tot();
    }
}


//减持股票,减持的数量,和当时的价格
void stock::sell(long num, double price)
{
     if(num < 0)
     {
         cout << "number of shares sold can't be nagative; ";
         cout <<  " Transaction is aborted.\n";
     }
     else if(num > shares)
     {
         cout << "you can't sell more than you have! transaction is aborted.\n";
     }
     else
     {
         shares -= num;
         share_val = price;
         set_tot();
     }
}

//更新股票的价格
void stock::update(double price)
{
    share_val = price;
    set_tot();
}


//显示股票的信息
void stock::show()
{
    cout << "Company: " << company << " Shares: " << shares << endl;
    cout << "Share price: " << share_val << " Total Worth: " << total_val << endl;
}

 公有属性的函数没什么好说的,看代码和注释就看的明白。里面有个特别一点的函数set_tot()函数,是计算股票总资产的,这个函数是类的私有成员函数,代码中每个公有成员函数都有使用它,方法都是一样的,就没必要写重复的代码,这样既减少了重复代码,有节省了空间。

三、将类应用于对象

经过头文件和源文件的编写,stock类已经创建好了,可以开始使用了,先创建两个类对象,kate与joe.

stock kate, joe;

 如何使用对象的成员函数

kate.show();
joe.show();

第一句调用kate对象的show()成员函数,这意味着此时的shares代表的是kate.shares,此时的share_val 代表的是kate.share_val 。第二句同理。

所创建的每个新对象都有自己的存储空间,用于存储其内部变量和类成员,但是同一个类的所有对象共享同一组类方法,也就是共用同一套类成员函数。kate和joe都是stock对象,kate.shares占一块内存,joe.shares占另外一块内存,它们是不一样的东西。

四、使用类

C++的目标是让使用类与使用基本的类型尽可能相同。要创建类对象,可以声明类变量,也可以使用new为类对象分配存储空间,可以将对象作为函数的参数和返回值,也可以将一个对象赋值给另一个对象。

下面是类的使用代码示例,创建一个stock对象 dreamer

#include 
#include "stock.h"

using namespace std;

int main()
{
    stock dreamer;
    dreamer.acquire("hengda", 20, 12.50); //dreamer以每股12.5元的价格买了20股恒大的股票
    dreamer.show();

    dreamer.buy(15, 18.25);//dreamer又以18.25元的价格增持了15股恒大的股票
    dreamer.show();

    dreamer.sell(400,20);//dreamer想以20元的价格卖掉400股,好像在做梦,都没有那么多股票
    dreamer.show();

    dreamer.buy(20000, 20);//dreamer突然有很多钱了,以每股20元的价格,一下子买了20000股恒大的股票
    dreamer.show();

    dreamer.sell(20000, 0.15);//完蛋了,恒大破产了,股票跌到1毛五,赶紧抛吧
    dreamer.show(); //变成穷光蛋了吧


    return 0;
}

输出结果

Company: hengda Shares: 20
Share price: 12.5 Total Worth: 250
Company: hengda Shares: 35
Share price: 18.25 Total Worth: 638.75
you can't sell more than you have! transaction is aborted.
Company: hengda Shares: 35
Share price: 18.25 Total Worth: 638.75
Company: hengda Shares: 20035
Share price: 20 Total Worth: 400700
Company: hengda Shares: 35
Share price: 0.15 Total Worth: 5.25

六、类的构造函数

其实上面创建的stock类还不完善,还需要为它添加构造函数与析构函数,为什么?

C++的目标是让使用类跟使用基本类型一样简单,但是到目前为止,我们还不能像初始化int变量那样初始化stock对象,也就是说常规的初始化语法不适用于stock类。

如int变量和结构体变量都可以这样初始化

int year = 2023; //int变量初始化

struct thing
{
    char* pn;
    int m;
};

thing amabob = {"wodget", -23};//结构体变量初始化

类对象可不能这么初始化

stock dreamer = {"hengda", 250, 2.5};

 类对象不能这么初始化,是因为数据部分的访问是私有的,这意味着程序不能直接访问数据成员。程序只能通过成员函数来访问数据成员,因此需要设计合适的成员函数,才能将对象初始化,这个合适的函数就是构造函数。

构造函数就是用于构造新对象,将值赋给它们的数据成员。

构造函数没有返回值,构造函数的名字与类名字一样;

还是延续前面的stock类,为其创建一个构造函数,需要为stock对象提供3个值,因此为构造函数提供3个参数,如果指向设置company成员,将其他的值设为0

stock::stock(const string& co, long n, double pr)
{
    company = co;
    
    if(n<0)
    {
        cout << "number of shares can't be nagative; ";
        cout << company << " shares set to 0.\n";
        shares = 0;
    }
    else
    {
        shares = n;
    }

    share_val = pr;
    set_tot();
}

 这个构造函数的代码与acquire()函数的代码相同,区别在于,程序声明对象的时候会自动调用构造函数。这个自动调用也不是那么的自动,还是要做一些工作。可以显式调用也可以隐式调用

显式调用构造函数

#include 
#include "stock.h"

using namespace std;

int main()
{
    stock dreamer = stock("apple",10, 12); //显式调用构造函数,将dreamer对象初始化

    dreamer.show();

    return 0;
}

 输出结果

Company: apple Shares: 10
Share price: 12 Total Worth: 120

隐式调用构造函数,就是在对象后面直接把参数贴上去

#include 
#include "stock.h"

using namespace std;

int main()
{
    stock dreamer("apple",10, 12); //隐式调用构造函数,将dreamer对象初始化

    dreamer.show();

    return 0;
}

输出结果是一样的 。

如果程序没有写构造函数,C++的编译器会提供一个默认的构造函数,里面没有初始的数据。

stock::stock() {}

当且仅当程序没有写任何构造函数,编译器才会提供一个默认构造函数,否则,就得自己写一个默认构造函数。

C++学习:类_第1张图片

C++学习:类_第2张图片

定义了常规构造函数和默认构造函数之后,声明一个类对象之后,如果没有调用常规构造函数,程序或自动调用默认构造函数

#include 
#include "stock.h"

using namespace std;

int main()
{
    stock dreamer; //程序调用默认构造函数

    dreamer.show();

    return 0;
}

 输出结果

Company: no name Shares: 0
Share price: 0 Total Worth: 0

 七、类的析构函数

用构造函数创建对象后,程序负责跟踪该对象,直到过期。对象过期时,程序将自动调用一个特殊的成员函数,这个函数就是析构函数,析构函数完成清理工作,如果构造函数使用new来分配内存,那么析构函数将使用delete释放内存。

西沟函数长这个样子

~stock();

 由于析构函数不用承担任何重要的工作,里面可以不放代码

stock::~stock()
{

}

如果你想看看西沟函数是否运行,可以在析构函数里面放一个打印语句

stock::stock()
{
    cout << "using ~stock().\n"
}

七、const成员函数

如果我们调用stock类对象的show函数,show()函数没有任何参数,如果定义的类对象是const的,那么有的编译器在调用show时会报错,因为编译器不知道show函数是否会修改调用的对象,保险的做法是在不会改变调用对象的函数后面加个const,如下所示

//显示股票的信息
void stock::show() const
{
    cout << "Company: " << company << " Shares: " << shares << endl;
    cout << "Share price: " << share_val << " Total Worth: " << total_val << endl;
}

 这样就保证了show函数不会修改调用的对象。

八、this指针

对于stock类,还有很多工作要做,到目前为止,每个类成员函数都只设计一个对象,即调用他的对象,但是有时候成员函数可能涉及到两个对象,在这种情况下需要使用C++的this指针。

虽然stock类声明可以显示数据,但它缺乏分析能力,例如从show()输出我们可以知道持有的哪一只股票价格最高,但是由于程序无法直接访问total_val,因此无法做出判断。要让程序知道存储的数据,最直接的方式是让成员函数返回一个值,为此,通常使用内联代码

class stock
{
private:
    ...
    double total_val;
    ...
public:
    double total() const { return total_val;}

    
};

 就直接程序访问而言,上述定义实际上是使total_val只读,也就是输可以使用方法total_val()来获得total_val的值,但这个类没有专门用于重新设置total_val值的方法。

const stock& stock::topval(const stock& s) const
{
    if(s.total_val > total_val)
        return s;
    else
        return *this;
}

 C++中通过引用this指针来解决这一问题,this指针指向用来调用成员函数的对象,this被作为隐藏参数传递给成员函数,这样调用stock1.topval(stock2)将this设置为stock1对象的地址,同样调用stock2.topval(stock1),将this设置为stock2对象的地址。

你可能感兴趣的:(C++,学习)