运算符重载的意义是:将常见的运算符重载出其他的含义:比如将*重载出指针的含义,将<<与cout联合使用重载出输出的含义,但需要认识到的问题是:运算符的重载:本质仍然是成员函数,即你可以认为:发生运算符重载时,实际上,是调用了成员函数,只不过重新换了个名字,叫运算符重载。
友元函数的意义:使得我们能够像成员函数一样访问私有成员变量,不会受到“权限”。下面通过一个函数来认识这一点:
1 # ifndef MYTIME3_H_H 2 # define MYTIME3_H_H 3 # include "iostream" 4 class Time 5 { 6 private: 7 int hours; 8 int minutes; 9 public: 10 Time(); 11 Time(int h, int m = 0); 12 void Addmin(int m); 13 void AddHr(int h); 14 void Reset(int h = 0, int m = 0); 15 Time operator+(const Time & t) const;//const放在后面表示不能修改成员函数 16 Time operator-(const Time & t) const; 17 Time operator*(double n) const; 18 friend Time operator*(double m, const Time & t) 19 { 20 return t*m; 21 }//类声明中定义的函数都是内联函数??? 22 friend std::ostream & operator<< (std::ostream & os, const Time & t); 23 }; 24 #endif
上述是一个关于类声明的头文件,在此,再次强调这么几个东西:
1 10,11行描述了构造函数(运用了函数重载),构造函数的存在意义是完成对类对象的初始化,在定义自己的类对象的时候,一定要保证了自己的类对象经过了初始化(实际上,在穿件类的时候,首先就会调用构造函数,完成初始化,即使没定义初始化函数,系统会自定生成一个初始化函数)
2 对于15-22行的代码,实际上都运用了运算符的重载,+,-,*,<<都被重载,至少从这里可以看出,运算符的重载,本质上,仍然是函数的调用。
3 18,22行的函数声明为友元函数,可以发现,friend 为关键字。同时注意:17行,18行代码,构成了函数重载!!!因为他们使用了同一个函数名,虽然这其中使用了运算符重载。这两个函数都描述了*运算,这也可以看出,重载函数,往往描述了同一种功能。
4 一个有趣的做法是:22行 的函数返回了一个ostream &,在之后的调用中,我们可以体会到这种妙用。
继续看成员函数定义:
1 # include "mytime3.h" 2 3 Time::Time() 4 { 5 hours = minutes = 0; 6 } 7 8 Time::Time(int h, int m) 9 { 10 hours = h; 11 minutes = m; 12 } 13 14 void Time::Addmin(int m) 15 { 16 minutes = minutes + m; 17 hours = minutes / 60; 18 minutes = minutes % 60; 19 } 20 21 void Time::AddHr(int h) 22 { 23 hours = hours + h; 24 } 25 26 void Time::Reset(int h, int m) 27 { 28 hours = h; 29 minutes = m; 30 } 31 Time Time::operator+(const Time& t) const 32 { 33 Time sum; 34 sum.minutes = minutes + t.minutes; 35 sum.hours = hours + t.hours + sum.minutes / 60; 36 sum.minutes = sum.minutes % 60; 37 return sum;//思考这里有引入Time对象的必要吗 38 } 39 40 Time Time::operator-(const Time& t) const 41 { 42 Time diff; 43 int tot1,tot2; 44 tot1 = t.minutes + 60 * t.hours; 45 tot2 = minutes + 60 * hours; 46 diff.hours = (tot2 - tot1) / 60; 47 diff.minutes = (tot2 - tot1) % 60; 48 return diff; 49 } 50 51 Time Time::operator*(double mult) const 52 { 53 Time result; 54 long totalminutes = hours*mult * 60 + minutes*mult; 55 result.hours = totalminutes / 60; 56 result.minutes = totalminutes % 60; 57 return result; 58 } 59 60 std::ostream & operator<<(std::ostream& os, const Time & t) 61 { 62 os << t.hours << "hours," << t.minutes << "minutes"; 63 return os; 64 }
需要注意的是:51行的*并不是描述友元函数那个,而是另外一个。同时注意到63行,返回了一个类对象的引用,返回引用,本质上其实就是返回了传递到引用的参数!!!
我们注意到:62中,我们直接访问了t.hour和t.minutes,这是因为我们定义的是友元函数,同时注意到,前面并没有Time::类作用域的限定。这说明了友元函数并不是成员函数。注意:函数定义中并没有使用friend关键字。
最后看实际上,调用了这个类的代码:
1 # include <iostream> 2 # include "mytime3.h" 3 4 int main() 5 { 6 using std::cout; 7 using std::endl; 8 Time aida(3, 35); 9 Time tosca(2, 48); 10 Time temp; 11 12 cout << "Aida and Tosca:" << endl; 13 cout << aida << ";" << tosca << endl; 14 temp = aida + tosca; 15 cout << "Aida + Tosca:" << temp << endl; 16 temp = aida*1.17; 17 cout << "Aida *1.17:" << temp << endl; 18 cout << "10.0*Tosca::" << 10.0*tosca << endl; 19 system("pause"); 20 return 0; 21 }
注意:第十行的 对象,被“隐“初始化
这里尤其要注意的是16行的代码,和18行的区别,当执行16行的代码时,系统会调用第一个*函数,当执行18行的代码时,执行的却是二个*函数。同时,我们注意:cout可以用来打印类对象,根本原因是std::ostream & operator<<(std::ostream& os, const Time & t)导致的,同时注意,该函数中返回了一个类对象引用,返回对象引用的目的是:返回cout本身,这就导致了比如定义了两个对象:Time A ,Time B ,当执行 cout<<A<<B时不会出错,因为(cout<<A)执行完毕返回了一个cout继续作用于B。你可以尝试删除return 。但是要运用这个的前提是:你认识到运算符重载本质上,仍然是函数的调用!!!只有认识到这点,才会将cout<<A<<B看成((cout<<A)<<B)
但问题在于:真的一定要使用友元函数吗,可以用合理的成员函数替代吗???