栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

从C到C++

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

从C到C++

对象和类(二)

上接:
对象和类(一)

1. 构造函数
//类1.h
#ifndef aa
#define aa

#include
#include
class Stock
{
    private:
        std::string company;//公司名
        long shares;//所持股票数量
        double share_val;//每股价格
        double total_val;//股票总价
        void set_tot()
        {
            total_val=shares*share_val;
        }
    public:
        void acquire(const std::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 hot={"Cam",100,50.25};这样初始化对象,这是因为类的数据成员都是私有的,所以我们无法直接访问数据成员。当然了,如果Stock类的数据成员都是公有的,我们自然能像结构体那样直接初始化对象。
实际上,我们发现我们Stock::acquire()函数,就是扮演着初始化的对象的角色。
C++给类提供了一个构造函数,专门用来创造和初始化对象的。

1.1 声明和定义构造函数
  Stock(const std::string &co,long n=0,double pr=0.0);//构造函数

上面这个就是构造函数的声明,这里使用了默认参数,我们发现构造函数的声明和成员函数的声明很像,但是注意,没有返回类型、构造函数的名称和类名称相同、构造函数是公有部分中的

Stock::Stock(const std::string &co,long n,double pr)
{
    company=co;
    if(n<0)
    {
        std::cout<<"数量不能是负数"
        < 

上面这个就是构造函数的定义,这段代码和acquire()的代码是一致的。

1.2 使用构造函数

C++提供了两种调用构造函数的方式。

  1. 显式调用
    Stock food = Stock("World",250,1.25);
    有没有发现啊?实际上这里利用了重载的技术,前面那个Stock是一个类,后面那个Stock是一个构造函数,而且我们发现构造函数的返回类型其实就是Stock类。
  2. 隐式调用
    Stock food("World",250,1.25);

我们也可以使用动态内存分配的方式创建类对象
Stock *pfood =new Stock("World",250,1.25);
但是有一点请注意:
构造函数不同于一般的成员函数,它不能使用诸如food.Stock("World",250,1.25)的方式调用构造函数。

1.3 默认构造函数

默认构造函数和非默认构造函数的差别巨大,而且默认构造函数和非默认构造函数一样重要。

  • 什么是默认构造函数?

    上一节所说的构造函数都是非默认构造函数,非默认构造函数的功能时提供对象初始化。
    默认构造函数的功能是,当对象未初始化时,给它进行默认初始化。

  • 为什么要有默认构造函数?

    C++禁止创建未初始化的对象。如果你只提供了非默认构造函数,那么Stock food;语句会直接报错,因为对象未初始化。但是如果你不提供非默认构造函数,那么Stock food;将不会报错,因为C++会提供隐式默认构造函数,自动给对象初始化。

  • 有两种默认构造函数

    隐式默认构造函数
    如果没有提供任何构造函数,C++将自动提供隐式默认构造函数,它的定义可能是
    Stock::Stock(){}
    隐式默认构造函数不做任何操作,它只是告诉编译器,“你看,对象初始化过了!”
    显式默认构造函数
    我们可以自己定义一个默认构造函数,这个就叫做显式默认构造函数
    一种简单的方法是,直接给非默认构造函数提供所有的默认参数,
    Stock(const std::string &co="Error!",long n=0,double pr=0.0);
    另一种方法是,利用构造函数的重载,显式默认构造函数原型:
    Stock();可以发现默认构造函数不接受任何参数。
    显式默认构造函数定义:
    Stock::Stock(){company="no name";shares=0;share_val=0.0;total_val=0.0;}
    当然了,为了重载解析成功,你只能二选一,两种方法仁者见仁,智者见智慧。

一般来说,类声明中,应该同时提供非默认构造函数和显式默认构造函数
这节所说的一切,本质上是函数重载,因为非默认构造函数和显式默认构造函数函数名相同,你调用哪个取决于语法。

Stock a;
Stock b("world",250,2.50);

上述代码中,对象a采用的是显式默认构造函数,对象b采用的是非默认构造函数。

2. 析构函数

析构函数完成清理工作,因此非常有用。
如果构造函数中使用new来创建数据,那么你必须写一个析构函数,用来delete各种数据项。当然了,如果你的构造函数中不使用动态内存分配,那么你完全不需要写析构函数。但是就算你不写析构函数,编译器也会自动给你生成一个什么也不干的隐式的默认析构函数。

  • 析构函数什么时候被调用?

    如果是静态对象,程序结束时,自动调用。
    如果是自动对象,代码段结束时,自动调用。
    如果是用new创建的对象,使用delete时自动调用。
    总之,析构函数是自动调用的

  • 析构函数的原型和实现
    ~Stock();可以看出来析构函数没有返回类型,而且不接受任何参数,析构函数的函数名是类名前加一个~

    Stock::~Stock(){
      cout<<"Bye!"< 
3. 改进Stock类
//类2.h
#ifndef aa
#define aa

#include
#include
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=0,double pr=0.0);//构造函数
        ~Stock();//析构函数
        void buy(long num,double price);//增持
        void sell(long num,double price);//卖出股票
        void update(double price);//更新股票价格
        void show();//显示信息

};


#endif
//类2.cpp
#include
#include"类2.h"
Stock::Stock()
{
    company="no name";
    shares=0;
    share_val=0.0;
    total_val=0.0;
    std::cout<<"注意!默认初始化!n";
}
Stock::Stock(const std::string &co,long n,double pr)
{   std::cout<<"注意!使用构造函数初始化,"<shares)
    {
        cout<<"卖出数量大于持有数量。交易失败。n";
    }
    else
    {
        shares-=num;
        share_val=price;
        set_tot();
    }
}
void Stock::update(double price){
    share_val=price;
    set_tot();
}
void Stock::show()
{
    using std::cout;
    using std::endl;
    using std::ios_base;
    ios_base::fmtflags orig=cout.setf(ios_base::fixed,ios_base::floatfield);
    std::streamsize prec =cout.precision(3);

    cout<<"公司:"< 
//类2main.cpp
#include
#include"类2.h"
int main()
{
    {
        using std::cout;
        using std::endl;
        cout<<"使用构造函数创建两个对象"< 
PS D:studyc++path_to_c++> g++ -I .include -o 类2 .类2.cpp .类2main.cpp
PS D:studyc++path_to_c++> .类2.exe
使用构造函数创建两个对象
注意!使用构造函数初始化,公司1
公司:公司1 股票数量:12
每股价格:$20.000 总价值:$240.00
注意!使用构造函数初始化,公司2
公司:公司2 股票数量:2
每股价格:$2.000 总价值:$4.00
把stock1赋值给stock2
显示stock1和stock2
公司:公司1 股票数量:12
每股价格:$20.000 总价值:$240.00
公司:公司1 股票数量:12
每股价格:$20.000 总价值:$240.00
使用构造函数给对象重新初始化
注意!使用构造函数初始化,公司3
注意!再见,公司3
重新显示stock1
公司:公司3 股票数量:10
每股价格:$50.000 总价值:$500.00
完成!
注意!再见,公司1
注意!再见,公司3
代码段结束

可以试着跑一下上面的程序,可能结果有不同,因为不同编译器对Stock stock2=Stock("公司2",2,2.0);的处理不同,这句话可能创建临时对象。
stock1=Stock("公司3",10,50.0);这句是赋值语句是一定会创建临时对象的。
所以说,通常来说,初始化比赋值更高效。

//类3.cpp
#include"类2.h"
#include"类2.cpp"

int main(){
    Stock a={"腾讯",100,45.0};
    a.show();
    Stock b{};
    b.show();
    const Stock c{"网易",200,25.00};
    //c.show();

}
注意!使用构造函数初始化,腾讯
公司:腾讯 股票数量:100
每股价格:$45.000 总价值:$4500.00
注意!默认初始化!
公司:no name 股票数量:0
每股价格:$0.000 总价值:$0.00
注意!使用构造函数初始化,网易
注意!再见,网易
注意!再见,no name
注意!再见,腾讯

可以看出来,列表初始化语法同样适用于类。
但是我这边注释掉了一段代码//c.show();,这段代码运行会出错。
因为,c是一个const对象,c.show()无法确保c的数据成员不被修改,所以编译器会报错。
那么,我们想到的方法肯定是–const形参,但是,正如你所见,show()函数,没有形参,该怎么办?
const成员函数
C++允许我们这样声明、定义const成员函数:
void show() const;

void Stock::show() const
{
  ...
}

实际上,C++的初始化语句非常多,源于运算符的重载。
下面看一个神奇的例子。
如果一个类的构造函数是Bozo(int a);,它的构造函数只接受一个参数,那么初始化语句可以这样写Bozo x=6;。
接受一个参数的构造函数允许使用赋值语法将对象初始化:
classname object = value;
这种语法有危险!。

4. this指针

到目前为止,每个类成员函数只涉及一个对象,即调用它的对象。但是我们有时候需要涉及多个对象,在这种情况下,必须使用this指针。
例如,我们要求一个函数实现比较两个股票的总价值,并选出大的那个股票。
那么这个成员函数的原型肯定是:
const Stock & topval(const Stock &s)const;
首先这肯定是const成员函数,其次它的肯定要接收一个Stock对象,返回值也必须是一个Stock对象。
那么,调用这个成员函数时,
top=stock1.topval(stock2)和top=stock2.topval(stock1)是等价的。
下面我们来看看函数如何定义?

const Stock & Stock::topval(const Stock& s)const
{
  if(s.total_val>total_val)
  {
    return s;
  }
  else
    return ???;
}

有没有发现问题?函数无法返回调用这个函数的对象本身。C++为了解决这个问题,提供了this指针。

  • this指针是什么?

    这是一种特殊指针,它指向调用函数的对象,也就是说this指针的值是调用对象的地址。
    每个成员函数都有一个this指针,*this就算调用对象。
    如果是const成员函数,那么我们无法用this指针修改调用对象。

则上面的函数应该这样定义:

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

这样一来,我们再次更新了我们的Stock类

5.对象数组

声明对象数组的方法和声明标准类型的数组的方法相同。

  • Stock类的最终版本
//类4.h
#ifndef aa
#define aa

#include
#include
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=0,double pr=0.0);//构造函数
        ~Stock();//析构函数
        void buy(long num,double price);//增持
        void sell(long num,double price);//卖出股票
        void update(double price);//更新股票价格
        void show() const;//显示信息
        const Stock & topval(const Stock & s)const;//返回价值更高的股票
};


#endif
//类4.cpp
#include
#include"类4.h"
Stock::Stock()
{
    company="no name";
    shares=0;
    share_val=0.0;
    total_val=0.0;

}
Stock::Stock(const std::string &co,long n,double pr)
{
    company=co;
    if(n<0)
    {
        std::cout<<"数量不能是负数"
        <shares)
    {
        cout<<"卖出数量大于持有数量。交易失败。n";
    }
    else
    {
        shares-=num;
        share_val=price;
        set_tot();
    }
}
void Stock::update(double price){
    share_val=price;
    set_tot();
}
void Stock::show() const
{
    using std::cout;
    using std::endl;
    using std::ios_base;
    ios_base::fmtflags orig=cout.setf(ios_base::fixed,ios_base::floatfield);
    std::streamsize prec =cout.precision(3);

    cout<<"公司:"<this->total_val)
    {
        return s;
    }
    else
        return *this;
}
//类4main.cpp
#include"类4.h"
int main(){
    Stock stocks[4]={
        {"公司1",12,20.0},
        {"公司2",200,2.0},
        {"公司3",130,3.25},
        {"公司4",60,6.5}
    };
    std::cout<<"展示对象数组:"<topval(stocks[i]);
    }
    std::cout<<"价值最高的股票是:"<show();
}
PS D:studyc++path_to_c++> g++ -I .include -o 类4 .类4.cpp .类4main.cpp
PS D:studyc++path_to_c++> .类4.exe      
展示对象数组:
公司:公司1 股票数量:12
每股价格:$20.000 总价值:$240.00
公司:公司2 股票数量:200
每股价格:$2.000 总价值:$400.00
公司:公司3 股票数量:130
每股价格:$3.250 总价值:$422.50
公司:公司4 股票数量:60
每股价格:$6.500 总价值:$390.00
价值最高的股票是:
公司:公司3 股票数量:130
每股价格:$3.250 总价值:$422.50
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1025458.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号