运算符重载ios
友元函数数组
重载<<运算符,以便于输出函数
状态成员学习
使用rand生成随机值spa
类的自动转换和强制类型转换指针
类转换函数code
本章首先介绍运算符重载,容许标准C++运算符用于类对象->友元,这种机制使得非成员函数能够访问私有数据->如何命令C++对类执行自动类型转换。对象
学习本章和12章将对类构造函数和类析构函数有更深刻的了解。作用域
以前介绍了函数重载,运算符重载是一种形式的C++多态。原型
实际上,不少C++运算符已经被重载,好比*地址运算符和乘法,C++根据操做数的数目和类型来决定采用哪一种操做。
能够定义一个表示数组的类,并重载+运算符。因而:
evening = sam + janet; // add two array objects;
要重载运算符,需遵照运算符函数的格式:
operator op(argument list)
eg:
operator +() operator *()
op必须是有效的C++运算符,不能虚构一个新的符号。
假设有一个Salesperson类,并重载了+运算符,使得两个对象的销售额相加:
districts = sid + sara; 至关于: districts = sid.operator+(sara);
而后该函数将隐式地使用sid(由于它调用了方法)而显式地使用sara对象(由于它被做为参数传递),来计算总和并返回。
2小时35分钟和2小时40分钟相加的运算符重载代码示例,
第7张经过定义结构相加来处理相似的状况,如今推广,采用类以及运算符重载来实现:
time.h #ifndef MYTIMED_H_ #define MYTIMED_H_ class Time { private: int hours; int minutes; public: 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; }; #endif ================ time.cpp #include<iostream> #include "time.h" Time::Time(){ hours = minutes = 0; } Time::Time(int h, int m) { hours = h; minutes = m; } void Time::Time::AddMin(int m) { // 一、分钟相加 // 二、分钟取模,结果为当前分钟 // 三、分钟除法,若结果大于0,小时加1 minutes += m; hours += minutes / 60; minutes = minutes % 60; } void Time::Time::AddHr(int h) { // 一、小时相加 // 二、小时取模,结果为当前小时 hours += h; hours = hours % 24; } void Time::Reset(int h, int m) { hours = h; minutes = m; } Time Time::Sum(const Time & t) const { Time sum; sum.minutes = minutes + t.minutes; sum.hours = hours + t.hours + sum.minutes/60; sum.minutes = sum.minutes % 60; // hours = hours % 24; return sum; } void Time::Show() const{ using std::cout; using std::endl; cout << "hours: " << hours <<endl; cout << "minutes: " << minutes <<endl; }
然而,返回值不能使引用,由于函数将建立一个新的Time对象。返回对象将建立对象的副本,而调用函数可使用它。
然而,若返回类型为Time &,因为sum是局部变量,在函数结束时被删除,所以引用将指向一个不存在的对象。
使用返回类型Time意味着程序将在删除sum以前构造它的拷贝,调用函数将获得该拷贝。
usetime.cpp #include<iostream> #include"time.h" int main() { using namespace std; Time planning; Time coding(2, 20); Time fixing(4, 20); Time sum; cout << "planning: " << endl; planning.Show(); cout << "coding: " << endl; coding.Show(); cout << "fixing: " << endl; fixing.Show(); cout << "sum: " << endl; sum = coding.Sum(fixing); sum.Show(); return 0; }
只需将sum()的名称改为operator+()便可。
这样,能够像调用Sum()那样来调用operator+()方法:sum = coding.operator+(fixing);
将该方法命令为operator+()后,也可使用运算符表示法:sum = coding+fixing;
time.h中
Time operator+(const Time & t) const;
time.cpp中
Time Time::operator+(const Time & t) const {
usetime.cpp中
sum = coding+fixing;
总之,operator+()函数的名称使得可使用函数表示法或运算符表示法来调用它。
能够将两个以上的对象相加吗?
t4 = t1 + t2 + t3;yes
运算符重载的限制:
至少有一个操做数是用户定义的类型;
使用运算符时不能违反运算符原来的句法规则;例如,不能将%重载成使用一个操做数;不能修改运算符的优先级;
不能建立新的运算符
不能重载下面的运算符
sizeof:sizeof运算符
.:成员运算符
*:成员指针运算符
:::做用域解析运算符
?::条件运算符
typeid:一个RTTI运算符
const_cast:强制类项转换运算符
dynamic_cast:强制类项转换运算符
reintcrpret_cast:强制类项转换运算符
static_case:强制类项转换运算符
表11.1中大多数运算符均可以经过成员或非成员函数进行重载,但下面的运算符只能经过成员函数进行重载:
=:赋值运算符
():函数调用运算符
[]:下标运算符
->:经过指针访问类成员的运算符
表11.1
。。。。。。。。
注意:在重载运算符时遵循一些明智的限制,eg:不能将*运算符重载成交换两个对象的数据成员。表示法中没有任何内容能够代表运算符完成的工做,所以最好定义一个其名称具备说明性的类方法,egswap();
好比乘法和减法;
time.h Time operator-(const Time & t) const; Time operator*(double a) const; ======================== time.cpp Time Time::operator-(const Time & t) const { Time diff; int tol1; int tol2; tol1 = t.minutes + t.hours * 60; tol2 = minutes + hours * 60; diff.minutes = (tol2 - tol1) % 60; diff.hours = (tol2 - tol1) / 60; return diff; } Time Time::operator*(double a) const { Time aa; int total = hours * 60 * a + minutes * a; aa.minutes = total % 60; aa.hours = total / 60; return aa; } ======================== usetime.cpp cout << "diff: " << endl; diff = coding-fixing; diff.Show(); cout << "result: " << endl; result = coding * 2; result.Show();
公有类方法提供私有部分的惟一访问途径,但这种限制太严格。
C++提供了另外一种形式的访问权限:友元。
友元函数;
友元类;
友元成员函数;
经过让函数成为类的友元,能够赋予该函数与类的成员函数相同的访问权限。只介绍友元函数,其余两种15章介绍。
为什么须要友元?在为类重载二元运算符时经常须要友元。
例如,乘法运算符将一个Time值与一个double值结合在一块儿。这限制了该运算符的使用方式。
A\B为Time类
A = B * 2.75;//能够这么使用,至关于A = B.operator*(2.75);
A = 2.75 * B; //不能够,由于2.75不是Time类
解决办法:
1、限制使用方式
2、非成员函数
非成员函数不是由对象调用的,它使用的全部值都是显示参数。
这样A = 2.75 * B;
与下面的非成员函数匹配:
A = operator*(2.75, B);
该函数的原型以下:
Time operator*(double m, const Time & t);
对于非成员重载运算符函数来讲,运算符表达式左边的操做数对应于运算符函数的第一个参数,运算符表达式右边的操做数对应于运算符函数的第二个参数。而原来的成员函数则按相反的顺序处理操做数。
使用非成员函数能够按所需的顺序得到操做数,但引起一个新问题:即非成员函数不能直接访问类的私有数据,至少常规非成员函数不能访问。然而,有一个特殊的非成员函数能够访问类的私有成员,称为友元函数
第一步:将其原型放在类声明中,并加上关键字friend
friend Time operator*(double m, const Time & t);
该原型意味着:
虽然operator*()函数是在类声明中声明的,但它不是成员函数,所以不能使用成员运算符来调用;
虽然operator*()不是成员函数,但它与成员函数的访问权限相同。
第二步:编写函数定义,不要使用Time::限定符,不要在定义中使用关键字friend
Time operator*(double m, const Time & t) { Time result; long totalminutes = (t.hours * 60 + t.minutes) * m; result.hours = totalminutes / 60; result.minutest =totalminutes % 60; return result; }
提示:若是要为类重载运算符,并将非类的项做为第一个操做数,则能够用友元函数来反转操做数的顺序。
能够对<<运算符重载,使之能与cout一块儿来显示对象的内容。eg:
cout << time;
实际上,它已经被重载不少次了。
最初,<<是位运算符;
ofstream类对该运算符进行了重载,用做输出,能识别全部的基本类型;
一、<<的第一种重载版本
要使Time类知道使用cout,必须使用友元函数。由于第一个操做数不是Time。
void operatorMM(ostream & os, const Time & t) { os << t.hours << " hours, " << t.minutes << " minutes"; } cout << time;