鸡啄米在上一节中讲了运算符重载为类的成员函数的方式和规则,这一节接着讲运算符重载的另一种方式--运算符重载为类的友元函数。

       在编程入门系列之二十二--友元中,鸡啄米讲到过,友元函数通过类的对象可以访问类的公有、保护和私有成员,也就是类的所有成员友元函数都能访问到。所以运算符重载为类的友元函数以后也可以访问类的所有成员。

       与运算符重载为成员函数时不同的是,重载的友元函数不属于任何类,运算符的操作数都需要通过函数的形参表传递。操作数在形参表中从左到右出现的顺序就是用运算符写表达式时操作数的顺序。

       这里也分双目运算符和单目运算符两种情况讨论运算符重载为友元函数的具体方式。

       如果有双目运算符U,它的其中一个操作数是类A的对象a,那么运算符U就可以重载为类A的友元函数,此友元函数的两个参数中,一个是类A的对象,另一个是其他对象,也可以是类A的对象。这样双目运算符重载为类的友元函数后,假设运算符的两一个操作数是对象b,则表达式a U b就相当于调用函数operator U(a, b)。

       下面再讨论单目运算符的重载。如果有前置单目运算符U,比如前置“--”,a为类A的对象,我们想实现U a这样的运算,就可以把U重载为类A的友元函数,此友元函数只有一个形参,为类A的对象,重载后表达式U a相当于调用函数operator U(a)。如果是后置单目运算符U,如后置“++”,a还是类A的对象,那么要实现a U这样的运算,也可以把U重载为类A的友元函数,此时友元函数就需要有两个形参,一个是类A的对象,另一个是整型形参,此整型形参没有实际意义,与上一节后置单目运算符重载为成员函数时的整型形参一样,只是为了区分前置运算符和后置运算符的重载。重载后表达式a U就相当于调用函数operator U(a, 0)。

       鸡啄米将上一节中第一个例子中的运算符重载改为友元函数,再简单介绍下要实现的功能:时间值的加法,比如2个小时20分钟加3个小时30分钟,应该是5个小时50分钟,运算规则就是小时数相加,分钟数相加,如果分钟数的和超过60分钟则小时数再加1,分钟数减60。双目运算符“+”需要重载为时间值类的友元函数,此函数有两个形参,类型都是时间值类的对象。


    鸡啄米:C++编程入门系列之四十七(多态性:运算符重载为类的友元函数)

       #include <iostream>
       using namespace std;
       class CTimeSpan
       {
       public:
                   CTimeSpan(int nHours=0, int nMins=0);      // 构造函数
                   friend CTimeSpan operator +(CTimeSpan ts1, CTimeSpan ts2); // 运算符“+”重载为成员函数
                   int GetHours()      { return m_nHours; }   // 获取小时数
                   int GetMins()       { return m_nMins; }    // 获取分钟数
                   void Show();                               // 显示时间值
       private:
                   int m_nHours;       // 小时数
                   int m_nMins;        // 分钟数
       };
       CTimeSpan::CTimeSpan(int nHours, int nMins)          // 构造函数的实现
       {
                  nHours += nMins/60;
                  nMins %= 60;
                  m_nHours = nHours;
                  m_nMins = nMins;
       }
       void CTimeSpan::Show()
       {
                 cout << m_nHours << "小时" << m_nMins << "分钟" << endl;
       }
       CTimeSpan operator +(CTimeSpan ts1, CTimeSpan ts2)  // 重载运算符函数实现
       {
                  int nNewHours;
                  int nNewMins;
                  nNewHours = ts1.m_nHours + ts2.m_nHours;
                  nNewMins = ts1.m_nMins + ts2.m_nMins;
                  nNewHours += nNewMins/60;
                  nNewMins %= 60;
                  return CTimeSpan(nNewHours, nNewMins);
       }
       int main()
       {
                 CTimeSpan timeSpan1(2, 50);
                 CTimeSpan timeSpan2(3, 30);
                 CTimeSpan timeSum;
                 timeSum = timeSpan1 + timeSpan2;
                 cout << "timeSpan1: ";
                 timeSpan1.Show();
                 cout << "timeSpan2: ";
                 timeSpan2.Show();
                 timeSum = timeSpan1 + timeSpan2;
                 cout << "timeSum=timeSpan1+timeSpan2: ";
                 timeSum.Show();
                 return 0;
       }

       程序运行结果:

       timeSpan1: 2小时50分钟
       timeSpan2: 3小时30分钟
       timeSum=timeSpan1+timeSpan2: 6小时20分钟

       这个程序的主函数main与上一节例子的main函数完全相同,程序运行结果也一样。区别就是加法运算符重载为CTimeSpan类的友元函数而不是成员函数,我们看到运算符重载函数有两个形参ts1和ts2,通过这两个参数将需要进行运算的操作数传递进去,而在此函数中也能够访问类CTimeSpan的私有成员m_nHours和m_nMins。

       这两节中鸡啄米给出的例子仅介绍了几个简单运算符的重载例子,对于其他如“%”、“>>”等运算符的重载可能有些不同,但是只要大家真正理解了重载方法,相信也很容易掌握其他运算符的重载。

       好了,运算符重载的内容就讲完了。如果有问题欢迎到鸡啄米博客交流讨论。