矢量类声明`
#ifndef VECTOR_H_
#define VECTOR_H_
#include<iostream>
namespace VECTOR
{
class Vector
{
public:
enum Mode {RECT , POL};
//枚举变量Mode, 默认RECT = 0, POL = 1
//RECT标识直角坐标系 , POL标识极坐标系
private:
double x;
double y;
double mag;
double ang;
Mode mode; //状态成员 ,控制构造函数、reset()方法、运算符重载函数使用那种形式
//这种成员是描述对象所处的状态
//一些供类内部使用的私有的方法
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 shove = Vector(100, 300); 但是使用构造函数修改属性,这里创建了一个临时对象,然后将其赋给shove
~Vector() {}
//以下是几个 内联的 常函数
double xval() const { return x; }
double yval() const { return y; }
double magval() const { return mag; }
double angval() const { return ang; }
//设置直角坐标/极坐标模式
void polar_mode() { mode = POL; }
void rect_mode() { mode = RECT; }
//运算符重载
//使用可以构造函数实现可以同时完成对矢量两种表达方式的修改
Vector operator+(const Vector& b) const; //形参的const确保对象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); //返回引用,链式编程
};
}
#endif // !VECTOR_H_
矢量类方法实现
#include "Vector.h"
#include<cmath>
using std::sqrt;
using std::sin;
using std::cos;
using std::atan; // (x)
using std::atan2; // (y/x) 返回值都是弧度
using std::cout;
namespace VECTOR
{
const double Rad_to_Deg = 45.0 / atan(1.0);
// should be about 57.2957795130823
//以下是四个私有方法,用来设置属性
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);
}
}
void Vector::set_x()
{
x = mag * cos(ang);
}
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 (mode == RECT)
{
x = n1;
y = n2;
set_mag();
set_ang();
}
else if (mode == POL)
{
mag = n1;
ang = n2;
set_x();
set_y();
}
else
{
cout << "第三个参数错误,将向量置0";
x = y = mag = ang = 0.0;
mode = RECT;
}
}
//用于修改对象
void Vector::reset(double n1, double n2, Mode form )
{
mode = form; //设置模式
if (mode == RECT)
{
x = n1;
y = n2;
set_mag();
set_ang();
}
else if (mode == POL)
{
mag = n1;
ang = n2;
set_x();
set_y();
}
else
{
cout << "第三个参数错误,将向量置0";
x = y = mag = ang = 0.0;
mode = RECT;
}
}
//运算符重载
Vector Vector::operator+(const Vector& b) const
{
//这里描述的是两个矢量相加,使用构造函数来完成最简单、最可靠
//注意:这里使用的是默认直角模式,可以同时修改x,y和幅值极角
//这里仅仅是为了修改属性的值,所以用哪种模式无所谓
return Vector(this->x + b.x, this->y + b.y);
//这里使用有参构造函数创建了一个无名的新对象,并返回了该对象的副本
//这确保了新对象是根据构造函数制定的标准创建的。
}
/*********************************************************
如果某方法通过计算得到了一个新的类对象,则应考虑该方法是否能通过
调整传入参数来使用构造函数来实现,这样实现最简洁、可靠、正确。
**********************************************************/
//用下面这种方法完成也是一样的,但是比较麻烦
/**********************************************
Vector Vector::operator+(const Vector& b) const
{
Vector sum;
sum.x = this->x + b.x;
sum.y = this->y + b.y;
sum.set_mag();
sum.set_ang();
return sum; //值传递方式返回一个新对象
}
***********************************************/
//-运算符可以进行量操作数相减和单操作数取反两种操作,所以这里进行两种重载
//向量相减
Vector Vector::operator-(const Vector& b) const
{
return Vector(this->x - b.x, this->y - b.y);
}
//向量取反
Vector Vector::operator-() const
{
return Vector(-this->x , -this->y );
}
//相乘顺序为 a * n; 并返回一个无名新对象的拷贝
Vector Vector::operator*(double n) const
{
return Vector(this->x * n, this->y * n);
}
//使用一个非成员友函数来 允许不同的相乘顺序 ,n * a
Vector operator*(double n, const Vector& a)
{
return a * n; //调用成员函数实现的运算符重载,这种写法最简洁
}
//返回对象本身,(os << v) == os , (os << v2) == os , ... 链式编程
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;
}
}
醉鬼漫步程序
#include<iostream>
#include<cstdlib> //rand() , srand(), prototype
#include<ctime> //time() prototype
#include<fstream>
#include"Vector.h"
int main()
{
using namespace std;
using VECTOR::Vector; //使用using声明使名称空间中的类可用
srand(time(0)); //随机数种子
double direction;
Vector step; //记录每一步的情况(矢量表示)
Vector resualt(0.0, 0.0); //使用resualt矢量记录前进情况
unsigned long steps = 0; //记录行走的步数
double dstep; //用户输入的步长
double target;
ofstream fout;
fout.open("thewalk.txt");
cout << "Enter target distance (q to quit): ";
while (cin >> target) //这里其实没有做q退出的功能,不是数字就退出
{
cout << "Enter the step length: ";
if (!(cin >> dstep)) //输入dstep ,并对可能发生的进行错误处理
{
break;
}
while (resualt.magval() < target)
{
direction = rand() % 360; //获取0-359的角度值
step.reset(dstep, direction, Vector::POL);
resualt = resualt + step; //使用resualt矢量记录前进情况,这里将矢量设置为直角坐标模式
steps++;
}
cout << "After " << steps << " steps, the subject has the following location:\n";
cout << resualt << endl;
resualt.polar_mode();
cout << "or\n" << resualt << endl;
cout << "Average outwards distance per step = " << resualt.magval() / steps << endl;
fout << resualt << endl; //写入到文件中,其实是调用友元函数operator<<(fout,result)
steps = 0;
resualt.reset(0.0, 0.0);
cout << "Enter target distance (q to quit): ";
}
cout << "Bye!\n";
cin.clear();
while (cin.get() != '\n') //等待回车键
continue;
return 0;
}