天天看點

多态性:運算符重載為類的友元函數

       友元函數通過類的對象可以通路類的公有、保護和私有成員,也就是類的所有成員友元函數都能通路到。是以運算符重載為類的友元函數以後也可以通路類的所有成員。

       與運算符重載為成員函數時不同的是,重載的友元函數不屬于任何類,運算符的操作數都需要通過函數的形參表傳遞。操作數在形參表中從左到右出現的順序就是用運算符寫表達式時操作數的順序。

       這裡也分雙目運算符和單目運算符兩種情況讨論運算符重載為友元函數的具體方式。

       如果有雙目運算符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。雙目運算符“+”需要重載為時間值類的友元函數,此函數有兩個形參,類型都是時間值類的對象。

  1.   #include <iostream>
  2.        using namespace std;
  3.        class CTimeSpan
  4.        {
  5.        public:
  6.                    CTimeSpan(int nHours=0, int nMins=0);      // 構造函數
  7.                    friend CTimeSpan operator +(CTimeSpan ts1, CTimeSpan ts2); // 運算符“+”重載為成員函數
  8.                    int GetHours()      { return m_nHours; }   // 擷取小時數
  9.                    int GetMins()       { return m_nMins; }    // 擷取分鐘數
  10.                    void Show();                               // 顯示時間值
  11.        private:
  12.                    int m_nHours;       // 小時數
  13.                    int m_nMins;        // 分鐘數
  14.        };
  15.        CTimeSpan::CTimeSpan(int nHours, int nMins)          // 構造函數的實作
  16.        {
  17.                   nHours += nMins/60;
  18.                   nMins %= 60;
  19.                   m_nHours = nHours;
  20.                   m_nMins = nMins;
  21.        }
  22.        void CTimeSpan::Show()
  23.        {
  24.                  cout << m_nHours << "小時" << m_nMins << "分鐘" << endl;
  25.        }
  26.        CTimeSpan operator +(CTimeSpan ts1, CTimeSpan ts2)  // 重載運算符函數實作
  27.        {
  28.                   int nNewHours;
  29.                   int nNewMins;
  30.                   nNewHours = ts1.m_nHours + ts2.m_nHours;
  31.                   nNewMins = ts1.m_nMins + ts2.m_nMins;
  32.                   nNewHours += nNewMins/60;
  33.                   nNewMins %= 60;
  34.                   return CTimeSpan(nNewHours, nNewMins);
  35.        }
  36.        int main()
  37.        {
  38.                  CTimeSpan timeSpan1(2, 50);
  39.                  CTimeSpan timeSpan2(3, 30);
  40.                  CTimeSpan timeSum;
  41.                  cout << "timeSpan1: ";
  42.                  timeSpan1.Show();
  43.                  cout << "timeSpan2: ";
  44.                  timeSpan2.Show();
  45.                  timeSum = timeSpan1 + timeSpan2;
  46.                  cout << "timeSum=timeSpan1+timeSpan2: ";
  47.                  timeSum.Show();
  48.                  return 0;
  49.        }

       程式運作結果:

       timeSpan1: 2小時50分鐘

       timeSpan2: 3小時30分鐘

       timeSum=timeSpan1+timeSpan2: 6小時20分鐘

       這個程式的主函數main與前面例子的main函數完全相同,程式運作結果也一樣。差別就是加法運算符重載為CTimeSpan類的友元函數而不是成員函數,我們看到運算符重載函數有兩個形參ts1和ts2,通過這兩個參數将需要進行運算的操作數傳遞進去,而在此函數中也能夠通路類CTimeSpan的私有成員m_nHours和m_nMins。