C++ 学习日志 --17

第十章 对象和类(中)

10.4 this 指针

到目前为止,每个类成员函数都只涉及一个对象,即调用它的对象。但有时候方法可能设计到多个对象,这是就需要使用this指针。依然以之前的股票模型为例。我们可以使用show()来输出手中持有股票价格最高的股票,但是由于程序无法直接访问total_val(),因此无法作出判断。要让程序知道储存的数据,最直接的方法是让方法返回一个值。比如:

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

这样我们可以查看到这个对象的总价值,但是如果我们要比较两个对象的股价,用这样的方法会有点麻烦。下面将介绍使用this指针来完成这样的操作。

程序 10.7 stock20.h

// stock20.h -- augmented version
#ifndef STOCK20_H_
#define STOCK20_H_
#include <string>

class Stock
{
private:
    std::string company;
    int shares;
    double share_val;
    double total_val;
    void set_tot() { total_val = shares * share_val; }

public:
    Stock(/* args */);
    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 prive);
    void show() const;
    const Stock &topval(const Stock &s) const;
};
#endif

程序 10.8 stock20.cpp

// stock20.cpp -- augmented version
#include <iostream>
#include "stock20.h"

// constructors
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 << "Number os shares can't be negative;"
                  << company << " shares set to 0.\n";
        shares = 0;
    }
    else
        shares = n;
    share_val = pr;
    set_tot();
}

// class destructor
Stock::~Stock() {}

// other methods
void Stock::buy(long num, double price)
{
    if (num < 0)
    {
        std::cout << "Number of shares purchased can't be negative. "
                  << "Transaction is aborted.\n";
    }
    else
    {
        shares += num;
        share_val = price;
        set_tot();
    }
}

void Stock::sell(long num, double price)
{

    if (num < 0)
    {
        std::cout << "Number of shares sold can't be negative. "
                  << "Transaction is aborted.\n";
    }
    else if (num > shares)
    {
        std::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() const
{
    using std::cout;
    using std::ios_base;

    // set format to #.###
    ios_base::fmtflags orig =
        cout.setf(ios_base::fixed, ios_base::floatfield);
    std::streamsize prec = cout.precision(3);

    cout << "Company: " << company
         << "\n Shares: " << shares
         << "\n Share Price: $" << share_val;
    // set format to #.##
    cout.precision(2);
    cout << "\n Total Worth: $" << total_val << '\n';

    // restore original format
    cout.setf(orig, ios_base::floatfield);
    cout.precision(prec);
}

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

为了验证this指针是否有用,我们需要再一个包含对象数组的程序中使用着用新方法。

10.5 对象数组

像变量一样,对象也可以创建一个数组。声明方法与之前的标准数组一样。

Stock mystuff[4];   // creates an array of 4 Stock objects

下面用程序来做演示:

程序 10.9 usestock2.cpp

// usestock2.cpp -- useing the stock class
// compile with stock20.cpp
#include <iostream>
#include "stock20.h"

const int STKS = 4;

int main(int argc, char const *argv[])
{
    // create an array of initialized objects
    Stock stocks[STKS] =
        {
            Stock("NanoSmart", 12, 20.0),
            Stock("Boffo Objects", 200, 2.0),
            Stock("Monolithic Obelisks", 130, 3.25),
            Stock("Fleep Enterprises", 60, 3.5)};

    std::cout << "Stock holdings:\n";
    int st;
    for (st = 0; st < STKS; st++)
        stocks[st].show();
    // set pointer to first element
    const Stock *top = &stocks[0];
    for (st = 1; st < STKS; st++)
        top = &top->topval(stocks[st]);
    // now top points to the most valuable holding
    std::cout << "\nMost valueable holding: \n";
    top->show();

    return 0;
}

程序输出:

Company: NanoSmart    
 Shares: 12
 Share Price: $20.000 
 Total Worth: $240.00 
Company: Boffo Objects
 Shares: 200
 Share Price: $2.000  
 Total Worth: $400.00 
Company: Monolithic Obelisks
 Shares: 130
 Share Price: $3.250
 Total Worth: $422.50
Company: Fleep Enterprises
 Shares: 60
 Share Price: $3.500
 Total Worth: $210.00

Most valueable holding:
Company: Monolithic Obelisks
 Shares: 130
 Share Price: $3.250

程序说明:

在上面的函数中,对象数组的概念比较简单,这里就不加说明了。重点来讲一下this指针。this指针出现在程序stock20.cpp中的topval()函数中

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

这个函数的定义中,返回值是Stock类的地址,参数是一个Stock类对象的引用。而最后的返回值*this是调用topval()函数的这个对象的地址。

10.6 类作用域

在类中定义名称(如类数据成员名和类成员函数名)的作用域都是整个类,作用域为整个类的名称旨在该类中是已知的,在类外是不可知的。

10.6.1 作用域为类的常量

有时候,是符号常用的作用域为类很有用。例如,类声明可能使用字面值 12 来定义数组的长度,由于该常量对于所有对象来说都是相同的,因此创建一个由所有对象共享的常量是一个不错的主义。于是进行了下列的操作:


class Bakery
{
    private:
        const int Months = 12;      // declare a constant? FAILS
        double cost [Months];
        ...
}

但是这样是行不通的,因为声明类只是描述了对象的形式,并没有创建对象。因此,在创建对象前,将没有用于储存值的空间。然而,有两种方式可以实现这个目标,兵器效果相同。

第一种是在类中声明一个枚举。在类声明中声明的枚举的作用域为整个类,因此可以用枚举为整型常量提供作用域为整个类的符号名称。即进行下面的代码操作:

class Bakery
{
    private:
        enum {Month = 12};
        double cost [Months];
        ...
}

上面枚举不对创建类数据成员,对于这个类而言,`Months`只是一个符号名称,在作用域为整个类的代码中遇到它,编译器将用30来替换他。

另外一种方式在类中定义常量是使用`static`关键词:

```cpp

class Bakery
{
    private:
    static const int Month = 12;
    double cost [Month];
}

这里创建了一个名为 Month的常量,该常量将与其他静态常量储存在一起,而不是储存在对象中。因此只有一个Month常量,被所有的对象共享。

10.6.2 作用域内枚举

使用传统的枚举方法如:


enum egg{Small, Medium, Large, Jumbo};
enum t_shirt{Small, Medium, Large, Jumbo};

上面的这段代码,编译器将无法通过,因为egg Smallt_shirt Small位于相同的作用域内,它们将发生冲突。为了避免这样的问题,我们应该使枚举量的作用域为类。

enum class egg{Small, Medium, Large, Jumbo};
enum class t_shirt{Small, Medium, Large, Jumbo};

这样,我们就可以使用作用域解析符(:

上一篇:redis学习之redis问题及解决方案


下一篇:redis分布式锁的实现