什么时候用this指针
到目前为止,每个类成员函数都只涉及一个对象,即调用它的对象。但有时候方法可能涉及到两个对象,需要使用this指针。
引言
Stock类中,show()的输出可以知道持有的哪一支股票价格最高,但由于程序无法直接访问total_val,因此无法作出判断。通过内联函数,让方法返回一个值,让程序知道存储的数据。
class Stock
{
private:
...
double total_val;
...
public:
double total() const { return total_val; }
...
};
使用total_val()方法来获得total_val的值,但这个类没有提供专门用于重新设置shares和share_val的值的方法,所以上述定义实际上是使total_val为只读。
了解this指针的方法
通过将该函数添加到类声明中,可以让程序查看一系列股票,找到价格最高一支。
也可以通过另一种方法,定义一个成员函数,它查看两个Stock对象,并返回股价较高的那个对象的引用。
遇到的问题
● 如何将两个要比较的对象提供给成员函数?
假设将该方法命名为topval(),则函数调用stock1.topval()将访问stock1对象的数据,而stock2.topval()将访问stock2对象的数据。如果希望该方法对两个对象进行比较,则必须将第二个对象作为参数传递给它。topval()使用类型为const Stock &的参数,按引用来传递参数,效率更高。
● 如何将方法的答案传回给调用程序呢?
让方法返回一个引用,该引用指向股价总值较高的对象。
const Stock &topval(const Stock &s) const;
该函数隐式访问一个对象,而显式访问另一个对象,并返回其中一个对象的引用。括号中的const表明,该函数不会修改被显式访问的对象;而括号后的const表明,该函数不会修改被隐式地访问的对象。由于返回了两个const对象之一的引用,因此返回类型也应为const引用。
假设要对Stock对象stock1和stock2进行比较,并将其中股价总值较高的那一个赋给top对象,则可以可以使用下面两条语句之一:
top = stock1.topval(stock2);
top = stock2.topval(stock1);
第一种格式隐式访问stock1,而显式访问stock2;第二种格式显式访问stock1,隐式访问stock2。
topval()的实现有个小问题
const Stock &Stock::topval(const Stock &s) const
{
if(s.total_val > total_val)
return s;
else
return ???;
s.total_val是作为参数传递的对象的总值,total_val是调用该方法的对象的总值。如果s.total_val大于total_val,则函数将返回指向s的引用;否则,将返回用来调用该方法的对象。
● 如何称呼该对象?
如果调用stock1.topval(stock2),则s是stock2的引用,但stock1没有别名。
解决问题方法——this指针
this指针指向用来调用成员函数的对象(this被作为隐藏参数传递给方法)。函数调用stock1.topval(stock2)将this设置为stock1对象的地址,使得这个指针可用于topval()方法。所有的类方法都将this指针设置为调用它的对象地址。topval()中的total_val只不过是this->total_val的简写。
注意:每个成员函数(包括构造函数和析构函数)都有一个this指针。this指针指向调用对象。如果方法需要引用整个调用对象,则可以使用表达式*this
。在函数的括号后面使用const限定符将this限定为const,这样将不能使用this来修改对象的值。然后,要返回的并不是this,因为this是对象的地址。而是对象本身即*this
(将解除引用运算符*
用于指针,将得到指针指向的值)。
const Stock &Stock::topval(const Stock &s) const
{
if(s.total_val > total_val)
return s; //参数对象
else
return *this; //调用对象
}
返回类型为引用意味着返回的是调用对象本身,而不是其副本。
stock20.h
#ifndef STOCK20_H
#define STOCK20_H
#include <string>
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:
Stock(); //默认构造函数
Stock(const 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 // STOCK20_H
stock20.cpp
#include <iostream>
#include "stock20.h"
using namespace std;
//默认构造函数
Stock::Stock()
{
cout << "Default constructor called\n";
company = "no name";
shares = 0;
share_val = 0.0;
total_val = 0.0;
}
//构造函数
Stock::Stock(const string &co, long n, double pr)
{
company = co;
if(n < 0)
{
cout << "Number of shares can't be negative; "
<< company << " shares set to 0.\n";
shares = 0;
}
else
shares = n;
share_val = pr;
set_tot();
}
//析构函数
Stock::~Stock() //不执行任何操作
{
}
void Stock::buy(long num, double price)
{
if(num < 0)
{
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)
{
cout << "Number of shares sold can't be negative. "
<< "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() const
{
//设置格式#.###
ios_base::fmtflags orig = cout.setf(ios_base::fixed, ios_base::floatfield);
streamsize prec = cout.precision(3);
cout << "Company: " << company
<< " Shares: " << shares << '\n';
cout << " Share Price: $" << share_val;
//设置格式#.##
cout.precision(2);
cout << " Total Worth: $" << total_val << '\n';
//重置原格式
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;
}
main.cpp
#include <iostream>
#include "stock20.h"
using namespace std;
int main()
{
//添加这两大括号,两个析构函数调用将在到达返回语句前执行
//如果没有这些大括号,将执行完整个main()后,才调用析构函数,即在两个析构函数调用前关闭则无法看到最后两条消息
{
cout << "Using constructors to create new objects\n";
Stock stock1("NanoSmart", 12, 20.0);
stock1.show();
Stock stock2 = Stock("Boffo Objects", 2, 2.0);
stock2.show();
cout << "Assigning stock1 to stock2:\n";
//将一个对象赋给同类型的另一个对象,其源对象的每个数据成员的内容复制到目标对象中相应的数据成员中
stock2 = stock1;
cout << "Listing stock1 and stock2:\n";
stock1.show();
stock2.show();
cout << "Using a constructor to reset an object\n";
//将新值赋给它,构造函数创建一个新的、临时的对象,然后赋值给stock1.随后程序调用析构函数,以删除该临时对象
stock1 = Stock("Nifty Foods", 10, 50.0);
cout << "Revised stock1:\n";
stock1.show();
cout << "Done\n";
}
return 0;
}