使用类
(3) 重载运算符: 作为成员函数还是非成员函数
对于很多运算符来说,可以选择使用成员函数或非成员函数来实现运算符重载。 一般来说,非成员函数应是友元函数,这样它才能直接访问类的私有数据。 例如,Time类的加法运算符在Time类声明中的原型如下:
Timeoperator+(constTime & t) const; //成员函数版本
这个类也可以使用下面的原型:
//非成员函数版本
friendTimeoperator+(constTime & t1, constTime & t2);
加法运算符需要两个操作数。 对于成员函数版本来说,一个操作数通过this指针隐式地传递,另一个操作数作为函数参数显式地传递;对于友元版本来说,两个操作数都作为参数来传递。
注意:非成员版本地重载运算符函数所需地形参数目与运算符使用地操作数数目相同;而成员版本所需地参数数目少一个,因为其中地一个操作数是被隐式地传递的调用对象。
这两个原型都与表达式T2+T3匹配,其中T2和T3都是Time类型对象。 也就是说,编译器将下面的语句:
T1=T2+T3;
转换为下面两个的任何一个:
T1=T2.operator+(T3); //成员函数
T1=operator+(T2,T3); //非成员函数
所以,在定义运算符时,必须选择其中的一种格式,而不能同时选择这两种格式,否则将被视为二义性错误。
(4) 矢量类
矢量的描述方式:
可以用大小(长度)和方向(角度)描述矢量;
可以用分量x和y表示矢量。
该类描述中将包含这两种表示形式。 另外,该程序使用枚举创建了两个常量(RECT和POL),用于标识两种表示法。
1. vector.h
//vect.h
#ifndef VECTOR_H_
#define VECTOR_H_
#include
namespace VECTOR
{
class Vector
{
public:
enum Mode{RECT,POL};
//RECT-直角坐标,POL-极坐标
private:
double x; //横坐标
double y; //纵坐标
double mag; //向量长度
double ang; //向量的方向(单位:度)
Mode mode; //直角坐标或极坐标
//设置变量值的私有方法
void set_mag();
void set_ang();
void set_x();
void set_y();
public:
Vector();
Vector(double n1, double n2, Mode form = RECT);
void reset(double n1, double n2, Mode form = RECT);
~Vector();
double xval() const { return x; } //返回x值
double yval() const { return y; } //返回y值
double magval() const { return mag; } //返回大小
double angval() const { return ang; } //返回角度
void polar_mode(); //将模式设置为极坐标
void rect_mode(); //将模式设置为直角坐标
//运算符重载
Vector operator+(const Vector & b) const;
Vector operator-(const Vector & b) const;
Vector operator-() const;
Vector operator*(double n) const;
//友元
friend Vector operator*(double n, const Vector & a);
friend std::ostream&operator<<(std::ostream & os, const Vector & v);
};
} //名称空间VECTOR结束
#endif // !VECTOR_H_
2. vector.cpp
Vector类存储了矢量的直角坐标和极坐标。 它使用名为mode的成员来控制使用构造函数、reset()方法和重载的operator<<()函数使用哪种形式,其中枚举RECT表示直角坐标模式(默认值)、POL表示极坐标模式。 这样的成员被称为状态成员(state member),因为这种成员描述的是对象所处的状态。
//vect.cpp -- Vector类的方法定义
#include
#include"vector.h" //包含了
using std::sqrt;
using std::sin;
using std::cos;
using std::atan;
using std::atan2;
using std::cout;
//利用名称空间的开放性,将方法定义添加到VECTOR名称空间中。
namespace VECTOR
{
//计算一弧度对应的角度
const double Rad_to_deg = 45.0 / atan(1.0);
//私有方法
//以x和y计算向量大小
void Vector::set_mag()
{
mag = sqrt(x*x + y * y);
}
void Vector::set_ang()
{
if (x == 0.0 && y == 0.0)
ang = 0.0;
else
ang = atan2(y, x);
}
//在极坐标系下计算x
void Vector::set_x()
{
x = mag * cos(ang);
}
//在极坐标系下计算y
void Vector::set_y()
{
y = mag * sin(ang);
}
//公有方法
Vector::Vector() //默认构造函数
{
x = y = mag = ang = 0.0;
mode = RECT;
}
//在直角坐标系下利用直角坐标构造矢量
//(默认)否则在极坐标系下利用极坐标构造矢量
Vector::Vector(double n1, double n2, Mode form)
{
mode = form;
if (form == RECT)
{
x = n1;
y = n2;
set_mag();
set_ang();
}
else if (form == POL)
{
mag = n1;
ang = n2 / Rad_to_deg;
set_x();
set_y();
}
else
{
cout << "Incorrect 3rd argument to Vector() -- ";
cout << "vector set to 0\n";
x = y = mag = ang = 0.0;
mode = RECT;
}
}
//在直角坐标系下(默认值)重设直角坐标
//或在极坐标系下重设极坐标
void Vector::reset(double n1, double n2, Mode form)
{
mode = form;
if (form == RECT)
{
x = n1;
y = n2;
set_mag();
set_ang();
}
else if (form == POL)
{
mag = n1;
ang = n2 / Rad_to_deg;
set_x();
set_y();
}
else
{
cout << "Incorrect 3rd argument to Vector() -- ";
cout << "vector set to 0\n";
x = y = mag = ang = 0.0;
mode = RECT;
}
}
Vector::~Vector() //析构函数
{
}
void Vector::polar_mode() //设为极坐标模式
{
mode = POL;
}
void Vector::rect_mode() //设为直角坐标
{
mode = RECT;
}
//运算符重载
//两个矢量求和
Vector Vector::operator+(const Vector & b) const
{
return Vector(x + b.x, y + b.y);
}
//矢量b减矢量a
Vector Vector::operator-(const Vector & b) const
{
return Vector(x - b.x, y - b.y);
}
//变换矢量的符号
Vector Vector::operator-() const
{
return Vector(-x, -y);
}
//将矢量乘以n
Vector Vector::operator*(double n) const
{
return Vector(n*x, n*y);
}
//友元方法
//将n乘以矢量a
Vector operator*(double n, const Vector & a)
{
return a * n;
}
//在RECT模式下显示直角坐标
//在POL模式下显示极坐标
std::ostream & operator<<(std::ostream & os, const Vector & v)
{
if (v.mode == Vector::RECT)
os << "(x,y) = (" << v.x << ", " << v.y << ")";
else if (v.mode == Vector::POL)
{
os << "(m,a) = (" << v.mag << ", "
<< v.ang*Rad_to_deg << ")";
}
else
os << "Vector object mode is invalid";
return os;
}
}//名称空间VECTOR结束
3. 使用Vector类来模拟随机漫步
//randwalk.cpp -- 使用Vector类
#include
#include //rand(),srand()原型
#include //time()原型
#include"vector.h"
int main()
{
using namespace std;
using VECTOR::Vector;
srand(time(0));
double direction;
Vector step;
Vector result(0.0, 0.0);
unsigned long steps = 0;
double target;
double dstep;
cout << "Enter target distance(q to quit): ";
while (cin >> target)
{
cout << "Enter step length: ";
if (!(cin >> dstep))
break;
while (result.magval() < target)
{
direction = rand() % 360;
step.reset(dstep, direction, Vector::POL);
result = result + step;
steps++;
}
cout << "After " << steps << " steps, the subject "
"has the following location:\n";
cout << result << endl;
result.polar_mode();
cout << "or\n" << result << endl;
cout << "Avergae outward distance per step = "
<< result.magval() / steps << endl;
steps = 0;
result.reset(0.0, 0.0);
cout << "Enter target distance (q to quit): ";
}
cout << "Bye!\n";
cin.clear();
while (cin.get() != '\n')
continue;
cin.get();
return 0;
}