- 运算符重载
- 友元函数
- 重载<<运算符
- 状态成员
- 使用rand()生成随机值
- 类的自动转换和强制类型转换
- 类转换函数
C++根据操作数的数目和类型决定采用哪种操作。
如果district2、sid和sara都是Salesperson类对象:
- 重载表示法:district2 = sid + sara;
- 函数表示法:distirct2 = sid.operator+(sara);
//程序清单 11.1 mytime0.h
#pragma once
#ifndef MYTIME0_H_
#define MYTIME0_H_
using namespace std;
class Time
{
public:
Time();
~Time();
Time(int h, int m = 0);
void AddMin(int m);
void AddHr(int h);
void Reset(int h = 0, int m = 0);
Time Sum(const Time& t) const;
void Show() const;
private:
int hours;
int minutes;
};
#endif // !MYTIME0_H_
//程序清单 11.2 #include#include "mytime0.h" Time::Time() { hours = minutes = 0; } Time::~Time() { } Time::Time(int h, int m) { hours = h; minutes = m; } void Time::AddMin(int m) { minutes += m; hours += minutes / 60; minutes %= 60; } void Time::AddHr(int h) { hours += h; } void Time::Reset(int h, int m) { hours = h; minutes = m; } Time Time::Sum(const Time& t) const { Time temp; temp.minutes = minutes + t.minutes; temp.hours = hours + t.hours + temp.minutes / 60; temp.minutes %= 60; return temp; } void Time::Show() const { cout << hours << " hours, " << minutes << " minutes.n"; }
Time Time::Sum(const Time& t) const
参数是引用,但返回类型不是,因为temp是临时对象。
不要返回指向局部变量或临时对象的引用。
//程序清单 11.3 #include11.2.1 添加加法运算符#include "mytime0.h" int main(void) { Time planning; Time coding(2, 40); Time fixing(5, 55); Time total; cout << "planning time = "; planning.Show(); cout << "coding time = "; coding.Show(); cout << "fixing time = "; fixing.Show(); total = coding.Sum(fixing); cout << "coding.Sum(fixing) = "; total.Show(); return 0; }
//程序清单 mytime1.h
#pragma once
#ifndef MYTIME1_H_
#define MYTIME1_H_
using namespace std;
class Time
{
public:
Time();
~Time();
Time(int h, int m = 0);
void AddMin(int m);
void AddHr(int h);
void Reset(int h = 0, int m = 0);
Time operator+(const Time& t) const; //operator+代替sum
void Show() const;
private:
int hours;
int minutes;
};
#endif // !MYTIME1_H_
#include#include "mytime1.h" Time::Time() { hours = minutes = 0; } Time::~Time() { } Time::Time(int h, int m) { hours = h; minutes = m; } void Time::AddMin(int m) { minutes += m; hours += minutes / 60; minutes %= 60; } void Time::AddHr(int h) { hours += h; } void Time::Reset(int h, int m) { hours = h; minutes = m; } Time Time::operator+(const Time& t) const { Time temp; temp.minutes = minutes + t.minutes; temp.hours = hours + t.hours + temp.minutes / 60; temp.minutes %= 60; return temp; } void Time::Show() const { cout << hours << " hours, " << minutes << " minutes.n"; }
#include11.2.2 重载限制#include "mytime1.h" int main(void) { Time planning; Time coding(2, 40); Time fixing(5, 55); Time total; cout << "planning time = "; planning.Show(); cout << "coding time = "; coding.Show(); cout << "fixing time = "; fixing.Show(); total = coding.operator+(fixing); //函数表示法 cout << "coding.Sum(fixing) = "; total.Show(); total = coding + fixing; //运算符重载表示法 cout << "coding + fixing = "; total.Show(); return 0; }
- 重载后的运算符至少有一个操作数是用户定义的类型,防止将标准类型重载运算符。
- 重载运算符不能违反原来的句法规则,不能修改优先级。
- 不能创建新的运算符。
- 不能重载的运算符:sizeof、成员运算符(.)、成员指针运算符(.*)、作用域解析运算符(::)、条件运算符(?:)
- 只能通过成员函数进行重载:赋值运算符(=)、函数调用运算符()、下标运算符[ ]、指针访问类成员运算符(->)
//程序清单 11.7 mytime2.h
#pragma once
#ifndef MYTIME2_H_
#define MYTIME2_H_
using namespace std;
class Time
{
public:
Time();
~Time();
Time(int h, int m = 0);
void AddMin(int m);
void AddHr(int h);
void Reset(int h = 0, int m = 0);
Time operator+(const Time& t) const;
Time operator-(const Time& t) const;
Time operator*(double mult) const;
void Show() const;
private:
int hours;
int minutes;
};
#endif // !MYTIME2_H_
//程序清单 11.8 #include#include "mytime2.h" Time::Time() { hours = minutes = 0; } Time::~Time() { } Time::Time(int h, int m) { hours = h; minutes = m; } void Time::AddMin(int m) { minutes += m; hours += minutes / 60; minutes %= 60; } void Time::AddHr(int h) { hours += h; } void Time::Reset(int h, int m) { hours = h; minutes = m; } Time Time::operator+(const Time& t) const { Time sum; sum.minutes = minutes + t.minutes; sum.hours = hours + t.hours + sum.minutes / 60; sum.minutes %= 60; return sum; } Time Time::operator-(const Time& t) const { Time diff; int tot1, tot2; tot1 = hours * 60 + minutes; tot2 = t.hours * 60 + t.minutes; diff.minutes = (tot1 - tot2) % 60; diff.hours = (tot1 - tot2) / 60; return diff; } Time Time::operator*(double mult) const { Time result; long totalminutes = hours * 60 * mult + minutes * mult; result.minutes = totalminutes % 60; result.hours = totalminutes / 60; return result; } void Time::Show() const { cout << hours << " hours, " << minutes << " minutes.n"; }
//程序清单 11.9 #include11.3 友元#include "mytime2.h" int main(void) { Time weeding(4, 35); Time waxing(2, 47); Time total, diff, adjusted; cout << "weeding time = "; weeding.Show(); cout << "waxing time = "; waxing.Show(); cout << "total work time = "; total = weeding + waxing; total.Show(); cout << "weeding time - wax time = "; diff = weeding - waxing; diff.Show(); cout << "adjusted work time = "; adjusted = total * 1.5; adjusted.Show(); return 0; }
友元有三种:
- 友元函数
- 友元类
- 友元成员函数
友元函数与类成员函数具有相同权限。(友元不是成员,胜似成员)
11.3.1 创建友元
- A = B * 2.75;
- A= B.operator*(2.75); //必须左侧为运算符对象,右侧为double类型
- A = 2.75 * B; //错误
friend Time operator*(double m, const Time & t);
- operator*()函数是在类声明中声明,但不是成员函数,不能使用成员运算符来调用
- operator*()函数不是成员函数,但与成员函数的访问权限相同
- 类声明中友元声明前加friend,友元函数定义时不使用friend,也不使用Time::限定符
- 编写非成员函数,都尽量写成友元函数
//程序清单 11.10 mytime3.h
#pragma once
#ifndef MYTIME3_H_
#define MYTIME3_H_
using namespace std;
class Time
{
public:
Time();
~Time();
Time(int h, int m = 0);
void AddMin(int m);
void AddHr(int h);
void Reset(int h = 0, int m = 0);
Time operator+(const Time& t) const;
Time operator-(const Time& t) const;
Time operator*(double mult) const;
friend Time operator*(double mult, const Time& t) { return t * mult; }
friend ostream& operator<<(ostream& os, const Time& t);
private:
int hours;
int minutes;
};
#endif // !MYTIME3_H_
//程序清单 11.11 #include#include "mytime3.h" Time::Time() { hours = minutes = 0; } Time::~Time() { } Time::Time(int h, int m) { hours = h; minutes = m; } void Time::AddMin(int m) { minutes += m; hours += minutes / 60; minutes %= 60; } void Time::AddHr(int h) { hours += h; } void Time::Reset(int h, int m) { hours = h; minutes = m; } Time Time::operator+(const Time& t) const { Time sum; sum.minutes = minutes + t.minutes; sum.hours = hours + t.hours + sum.minutes / 60; sum.minutes %= 60; return sum; } Time Time::operator-(const Time& t) const { Time diff; int tot1, tot2; tot1 = hours * 60 + minutes; tot2 = t.hours * 60 + t.minutes; diff.minutes = (tot1 - tot2) % 60; diff.hours = (tot1 - tot2) / 60; return diff; } Time Time::operator*(double mult) const { Time result; long totalminutes = hours * 60 * mult + minutes * mult; result.minutes = totalminutes % 60; result.hours = totalminutes / 60; return result; } ostream& operator<<(ostream& os, const Time& t) { os << t.hours << " hours " << t.minutes << " minutes"; return os; }
//程序清单 11.12 #include11.4 重载运算符:作为成员函数还是非成员函数#include "mytime3.h" int main(void) { Time aida(3, 35); Time tosca(2, 48); Time temp; cout << "aida and tosca: "; cout << aida << "; " << tosca << endl; temp = aida + tosca; cout << "aida + tosca = " << temp << endl; temp = aida * 1.17; cout << "aida * 1.17 = " << temp << endl; temp = 10.0 * tosca; cout << "10.0 * tosca = " << temp << endl; return 0; }
一般来说,非成员函数应是友元函数。
- Time operator+(const Time & t) const;
- friend Time operator+(const Time& t1, const Time& t2)
- 对于成员函数版本,一个操作数通过this指针隐式传递,另一个操作数作为函数参数显式传递
- 对于友元函数版本,两个操作数都作为参数传递
//程序清单 11.13 vector.h #pragma once #ifndef VECTOR_H_ #define VECTOR_H_ #includeusing namespace std; namespace VECTOR { class Vector { public: Vector(); ~Vector(); enum Mode { RECT, POL }; Vector(double n1, double n2, Mode form = RECT); void reset(double n1, double n2, Mode form = RECT); 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-(); Vector operator*(double mul) const; friend Vector operator*(double mul, const Vector& a); friend ostream& operator<<(ostream& os, const Vector& v); //review 7 operator double() const; private: double x, y; double mag, ang; Mode mode; void set_x(); void set_y(); void set_mag(); void set_ang(); }; } #endif // !VECTOR_H_
//程序清单 11.14 #include11.5.2 为Vector类重载算术运算符#include #include "vector.h" namespace VECTOR { const double Rad_to_deg = 45.0 / atan(1.0); //1弧度==?角度 void Vector::set_x() { x = mag * cos(ang); } void Vector::set_y() { y = mag * sin(ang); } void Vector::set_mag() { mag = sqrt(x * x + y * y); } void Vector::set_ang() { if (0 == x && 0 == y) //原点处 ang = 0; else ang = atan2(y, x); //结果为弧度制 } Vector::Vector() { x = y = mag = ang = 0; mode = RECT; } Vector::~Vector() { } Vector::Vector(double n1, double n2, Mode form) { mode = form; if (form == RECT) //切记== { x = n1; y = n2; set_ang(); set_mag(); } else if (form == POL) //切记== { mag = n1; ang = n2 / Rad_to_deg; set_x(); set_y(); } else { cout << "Incorrect! Vector set to 0n"; x = y = mag = ang = 0; mode = RECT; } } void Vector::reset(double n1, double n2, Mode form) { mode = form; if (form == RECT) //切记== { x = n1; y = n2; set_ang(); set_mag(); } else if (form == POL) //切记== { mag = n1; ang = n2 / Rad_to_deg; //弧度转换为角度 set_x(); set_y(); } else { cout << "Incorrect! Vector set to 0n"; x = y = mag = ang = 0; mode = RECT; } } 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-() { return Vector(-x, -y); }
Vector Vector::operator+(const Vector & b) const
{
Vector sum;
sum.x = x + b.x;
sum.y = y + b.y;
return sum;
}
升级:
Vector Vector::operator+(const Vector & b) const
{
Vector sum;
sum.x = x + b.x;
sum.y = y + b.y;
sum.set_ang(sum.x, sum.y);
sum.set_mag(sum.x, sum.y);
return sum;
}
升级:(调用构造函数)
Vector Vector::operator+(const Vector & b) const
{
return Vector(x + b.x, y + b.y);
}
如果方法通过计算返回一个新的类对象,可以考虑使用类构造函数完成。
11.5.4 使用Vector类模拟随机漫步//程序清单 11.15 #include11.6 类的自动转换和强制类型转换#include #include #include "vector.h" using namespace VECTOR; int main(void) { double target; double dstep; Vector result(0.0, 0.0); //默认起始在原点 double direction; srand(time(0)); //srand(time(NULL)) Vector step; unsigned long steps = 0; cout << "Enter target distance (q to quit): "; while (cin >> target) { cout << "Enter step length: "; if (!(cin >> dstep)) //输入0,原地不动 break; while (result.magval() < target) { direction = rand() % 360; //产生0~359度之间 step.reset(dstep, direction, Vector::POL); //在main中访问Vector类成员变量POL result = result + step; //向量和 steps++; //走多少步 } cout << "After " << steps << " steps, the subject has the following location:n"; cout << result << endl; result.polar_mode(); //坐标系转换 cout << result << endl << 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; }
//程序清单 11.16 stonewt.h #pragma once #ifndef STONEWT_H_ #define STONEWT_H_ #includeusing namespace std; class Stonewt { public: Stonewt(); ~Stonewt(); Stonewt(double lbs); //自动隐式转换 //explicit Stonewt(double lbs); //强制显式转换 Stonewt(int stn, double lbs); void show_lbs() const; void show_stn() const; private: enum {Lbs_per_stn = 14}; //static const int Lbs_per_stn = 14; int stone; double pds_left; double pounds; }; #endif // !STONEWT_H_
//程序清单 11.17
#include "stonewt.h"
Stonewt::Stonewt()
{
stone = pounds = pds_left = 0;
}
Stonewt::~Stonewt()
{
}
Stonewt::Stonewt(double lbs)
{
stone = int(lbs) / Lbs_per_stn;
pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);
pounds = lbs;
}
Stonewt::Stonewt(int stn, double lbs)
{
stone = stn;
pds_left = lbs;
pounds = stn * Lbs_per_stn + lbs;
}
void Stonewt::show_lbs() const
{
cout << pounds << " poundsn";
}
void Stonewt::show_stn() const
{
cout << stone << " stone, " << pds_left << " poundsn";
}
下面的构造函数用于将double类型的值转换为Stonewt类型:
Stonewt(double lbs);
也就是说,可以编写这样的代码:
Stonewt myCat;
myCat = 19.6;
程序使用构造函数Stonewt(double)创建临时的Stonewt对象,并将19.6作为初始化值。
随后逐成员赋值将该临时对象的内容赋值到myCat中。此过程为隐式转换,自动进行。
只有接收一个参数的构造函数才能作为转换函数,如果有两个参数,给第二个参数提供了默认值,也可以。
C++新增explicit关键字,关闭这种自动隐式转换,允许显式强制类型转换。
explicit Stonewt(double lbs);
Stonewt myCat;
myCat = 19.6; //错误
myCat = Stonewt(19.6);
myCat = (Stonewt)19.6;
//程序清单 11.18 #include11.6.1 转换函数#include "stonewt.h" int main(void) { Stonewt incognito = 275; //使用构造函数初始化 //Stonewt incognito(275); //Stonewt incognito = Stonewt(275); Stonewt wolfe(285.7); Stonewt taft(21, 8); cout << "The celebrity weighed: "; incognito.show_stn(); incognito.show_lbs(); cout << "The detective weighed: "; wolfe.show_stn(); wolfe.show_lbs(); cout << "The president weighed: "; taft.show_stn(); taft.show_lbs(); return 0; }
程序清单11.18将数字转换为Stonewt对象。
转换函数可以将Stonewt对象转换为某种类型。
转换函数是用户定义的强制类型转换。
例如:operator double ();
- 转换函数必须是类方法(类成员函数); 需要通过类对象调用
- 转换函数不能指定返回类型; double指出来要转换的类型,所以不需要
- 转换函数不能有参数。 类对象告知要转换的值,所以不需要
//程序清单 11.19 Stonewt1.h #pragma once #ifndef STONEWT1_H_ #define STONEWT1_H_ #includeusing namespace std; class Stonewt { public: Stonewt(); ~Stonewt(); Stonewt(double lbs); //自动隐式转换 //explicit Stonewt(double lbs); //强制显式转换 Stonewt(int stn, double lbs); void show_lbs() const; void show_stn() const; operator int() const; operator double() const; //强制显式转换 //explicit operator int() const; //explicit operator double() const; //review 1 Stonewt operator*(double mult) const; //review 4 friend Stonewt operator*(double mult, const Stonewt& s); private: //enum { Lbs_per_stn = 14 }; static const int Lbs_per_stn = 14; int stone; double pds_left; double pounds; }; #endif // !STONEWT1_H_
//程序清单 11.20
#include "stonewt1.h"
Stonewt::Stonewt()
{
stone = pounds = pds_left = 0;
}
Stonewt::~Stonewt()
{
}
Stonewt::Stonewt(double lbs)
{
stone = int(lbs) / Lbs_per_stn;
pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);
pounds = lbs;
}
Stonewt::Stonewt(int stn, double lbs)
{
stone = stn;
pds_left = lbs;
pounds = stn * Lbs_per_stn + lbs;
}
void Stonewt::show_lbs() const
{
cout << pounds << " poundsn";
}
void Stonewt::show_stn() const
{
cout << stone << " stone, " << pds_left << " poundsn";
}
Stonewt::operator int() const
{
return int(pounds + 0.5);
}
Stonewt::operator double() const
{
return pounds;
}
//review 1
Stonewt Stonewt::operator*(double mult) const
{
return Stonewt(pounds * mult);
}
//review 4
Stonewt operator*(double mult, const Stonewt& s)
{
return(mult * s.stone);
}
//程序清单 11.21 #include#include "stonewt1.h" int main(void) { Stonewt poppins(9, 2.8); double p_wt = poppins; //隐式转换 cout << "Convert to double => "; cout << "Poppins: " << p_wt << " pounds.n"; cout << "Covert to int => "; cout << "Popins: " << int(poppins) << " pounds.n"; //显式强制转换 return 0; }
应谨慎使用隐式转换,最好使用显式转换。



