书籍:C++ Primer Plus (第六版)(中文版)
开发工具:Dev-C++ 5.11
计算机配置:Intel Xeon CPU E5-2603 v3 @ 1.60GHz
系统信息:Windows 10 专业版,64位操作系统,基于x64的处理器
第11章 类的应用
11.4 运算符重载:成员函数与非成员函数的选择
在C++中,运算符重载可以通过类的成员函数或全局的非成员函数实现。选择哪种方式取决于具体需求。通常情况下,若运算符需要修改对象状态或自然地作用于左侧操作数,则定义为成员函数更合适;而当涉及类型转换、对称性操作(如两个操作数都可能被隐式转换),或需访问私有成员但不改变对象时,使用友元函数更为合理。
11.5 深入探讨运算符重载:构建矢量类
本节通过一个完整的vector类示例,展示如何合理设计并重载多个运算符,以支持直观的数学操作。该类支持直角坐标系(RECT)和极坐标系(POL)两种表示模式,并可在两者之间自动转换。
头文件定义:vector.h
#ifndef VECTOR_H_
#define VECTOR_H_
#include <iostream>
namespace VECTOR
{
class vector
{
public:
enum Mode { 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; }
double yval() const { return 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);
};
}
#endif
[此处为图片1]
实现文件:vector.cpp
#include <cmath>
#include "vector.h"
using std::sqrt;
using std::sin;
using std::cos;
using std::atan;
using std::atan2;
using std::cout;
namespace VECTOR
{
const double Rad_to_deg = 45.0 / atan(1.0);
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 (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);
}
vector vector::operator-(const vector & b) const
{
return vector(x - b.x, y - b.y);
}
vector vector::operator-() const
{
return vector(-x, -y);
}
vector vector::operator*(double n) const
{
return vector(n * x, n * y);
}
vector operator*(double n, const vector & a)
{
return a * n;
}
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;
}
}
[此处为图片2]
vector::vector()
{
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);
}
vector vector::operator-(const vector & b) const
{
return vector(x - b.x, y - b.y);
}
vector vector::operator*(double n) const
{
return vector(n * x, n * y);
}
vector operator*(double n, const vector & a)
{
return a * n;
}
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;
}
[此处为图片1]
randwalk.cpp
#include <iostream>
#include <cstdlib>
#include <ctime>
#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 << "Average 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;
return 0;
}
[此处为图片2]
运行结果示例: Enter target distance (q to quit): 50 Enter step length: 2 After 256 steps, the subject has the following location: (x,y) = (49.2231, -11.0343) or (m,a) = (50.4447, -12.635) Average outward distance per step = 0.19705 Enter target distance (q to quit): 50
Enter step length: 2 After 634 steps, the subject has the following location: (x,y) = (-43.8145, -25.971) or (m,a) = (50.9333, -149.343) Average outward distance per step = 0.0803365 Enter target distance (q to quit): 50 Enter step length: 1 After 399 steps, the subject has the following location: (x,y) = (-50.3994, -1.21405) or (m,a) = (50.4141, -178.62) Average outward distance per step = 0.126351 Enter target distance (q to quit): q Bye! -------------------------------- Process exited after 56.52 seconds with return value 0 请按任意键继续. . .
11.6 类型的自动转换与显式类型转换
在C++中,类可以支持从基本数据类型到类类型的自动转换,也可以通过构造函数实现隐式类型转换。此外,还可以定义强制类型转换操作来控制对象如何被转换为其他类型。
示例:11.6
文件:stonewt.h
#ifndef STONEWT_H_
#define STONEWT_H_
class Stonewt
{
private:
enum { Lbs_per_stn = 14 }; // 每英石包含的磅数
int stone; // 英石部分
double pds_left; // 剩余的磅数
double pounds; // 总重量(以磅为单位)
public:
Stonewt(double lbs); // 从磅构造
Stonewt(int stn, double lbs); // 从英石和磅构造
Stonewt(); // 默认构造函数
~Stonewt(); // 析构函数
void show_lbs() const; // 显示总磅数
void show_stn() const; // 显示英石和剩余磅数
};
#endif
文件:stonewt.cpp
#include <iostream>
#include "stonewt.h"
using std::cout;
Stonewt::Stonewt(double lbs)
{
stone = static_cast<int>(lbs) / Lbs_per_stn;
pds_left = static_cast<int>(lbs) % Lbs_per_stn + lbs - static_cast<int>(lbs);
pounds = lbs;
}
Stonewt::Stonewt(int stn, double lbs)
{
stone = stn;
pds_left = lbs;
pounds = stn * Lbs_per_stn + lbs;
}
Stonewt::Stonewt()
{
stone = 0;
pounds = 0;
pds_left = 0;
}
Stonewt::~Stonewt()
{
// 析构函数为空
}
void Stonewt::show_stn() const
{
cout << stone << " stone, " << pds_left << " pounds.\n";
}
void Stonewt::show_lbs() const
{
cout << pounds << " pounds.\n";
}
文件:stone.cpp
#include <iostream>
#include "stonewt.h"
using std::cout;
void display(const Stonewt &st, int n);
int main()
{
Stonewt incognito = 275; // 隐式转换:double → Stonewt
Stonewt wolfe(285.7); // 显式构造
Stonewt taft(21, 8); // 使用两个参数构造
cout << "The celebrity weighed ";
incognito.show_stn();
cout << "The detective weighed ";
wolfe.show_stn();
cout << "The President weighed ";
taft.show_lbs();
incognito = 276.8; // 赋值触发隐式转换
taft = 325; // 同样是隐式转换
cout << "After dinner, the President weighed ";
taft.show_lbs();
display(taft, 2); // 传递对象
cout << "The wrestler weighed even more.\n";
display(422, 2); // 临时对象由整数隐式创建
cout << "No stone left unearned\n";
return 0;
}
void display(const Stonewt &st, int n)
{
for (int i = 0; i < n; ++i)
{
cout << "Wow! ";
st.show_stn();
}
}
在程序运行后,得到了以下输出结果:
名人的体重为 19 英石 9 磅。
侦探的体重达到了 20 英石 5.7 磅。
总统先生的初始体重是 302 磅。
用餐之后,总统的体重上升至 325 磅。
令人惊讶的是,当前体重已达到 23 英石 3 磅。
再次确认:23 英石 3 磅。
[此处为图片1]而那位摔跤手的体重更是惊人。
竟然高达 30 英石 2 磅!
重复验证:30 英石 2 磅!
所有数据均被完整记录,无一遗漏。
示例代码 11.7
头文件 stonewt1.h
#ifndef STONEWT1_H_
#define STONEWT1_H_
class Stonewt
{
private:
enum { Lbs_per_stn = 14 };
int stone;
double pds_left;
double pounds;
public:
Stonewt(double lbs);
Stonewt(int stn, double lbs);
Stonewt();
~Stonewt();
void show_lbs() const;
void show_stn() const;
operator int() const;
operator double() const;
};
#endif
实现文件 stonewt1.cpp
#include <iostream>
#include "stonewt1.h"
using std::cout;
Stonewt::Stonewt(double lbs)
{
stone = static_cast<int>(lbs) / Lbs_per_stn;
pds_left = static_cast<int>(lbs) % Lbs_per_stn + lbs - static_cast<int>(lbs);
pounds = lbs;
}
Stonewt::Stonewt(int stn, double lbs)
{
stone = stn;
pds_left = lbs;
pounds = stn * Lbs_per_stn + lbs;
}
Stonewt::Stonewt()
{
stone = pounds = pds_left = 0;
}
Stonewt::~Stonewt()
{
}
void Stonewt::show_stn() const
{
cout << stone << " stone, " << pds_left << " pounds.\n";
}
void Stonewt::show_lbs() const
{
cout << pounds << " pounds.\n";
}
Stonewt::operator int() const
{
return static_cast<int>(pounds + 0.5);
}
Stonewt::operator double() const
{
return pounds;
}
主程序文件 stone1.cpp
#include <iostream>
#include "stonewt1.h"
int main()
{
using std::cout;
Stonewt poppins(9, 2.8);
double p_wt = poppins;
cout << "Convert to double => ";
cout << "poppins: " << p_wt << " pounds.\n";
cout << "Convert to int => ";
cout << "poppins: " << int(poppins) << " pounds.\n";
return 0;
}
编译并执行后的结果显示如下:
转换为 double 类型 => poppins: 128.8 磅。
转换为 int 类型 => poppins: 129 磅。
[此处为图片2]程序成功运行,耗时约 0.02376 秒,返回值为 0。
按任意键继续...


雷达卡


京公网安备 11010802022788号







