到目前为止,每个类成员函数都只涉及一个对象,即调用它的对象。但有时候方法可能设计到多个对象,这是就需要使用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
指针是否有用,我们需要再一个包含对象数组的程序中使用着用新方法。
像变量一样,对象也可以创建一个数组。声明方法与之前的标准数组一样。
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()
函数的这个对象的地址。
在类中定义名称(如类数据成员名和类成员函数名)的作用域都是整个类,作用域为整个类的名称旨在该类中是已知的,在类外是不可知的。
有时候,是符号常用的作用域为类很有用。例如,类声明可能使用字面值 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
常量,被所有的对象共享。
使用传统的枚举方法如:
enum egg{Small, Medium, Large, Jumbo}; enum t_shirt{Small, Medium, Large, Jumbo};
上面的这段代码,编译器将无法通过,因为egg Small
和t_shirt Small
位于相同的作用域内,它们将发生冲突。为了避免这样的问题,我们应该使枚举量的作用域为类。
enum class egg{Small, Medium, Large, Jumbo}; enum class t_shirt{Small, Medium, Large, Jumbo};
这样,我们就可以使用作用域解析符(: