2015年7月2日 星期四

Operator Overloading 運算子重載



在前幾篇的程式中,class myData 已初具動態記憶體管理的能力,然而它幾乎是個無用的 class,因為它只有一個公開的 add 函式可供外界把資料添加進去,沒有辦法取出資料。

若要讓它的資料可以被外部程式存取,可以設計一些 get() set() 等函式,不過看起來不夠簡潔;或者把內部的 int *data 改放到 public: 區段,但這樣又失去封裝的精神...

若是能像使用陣列,例如 a[15] 這樣的方式來存取物件內的資料,且存取機制又能在 class 內部作好管控,應該是比較好的方式。C++ 透過 Overloading 來滿足這類的設計需求。


下列 C++ 的運算子都可以 Overloading (重載) 
+ - * / % ^ & ~ ! = < > += -= *= /= ^= &= << >> >= <= == != && ++ -- [] () new delete | ||

在 class 中設計運算子 Overloading 的語法如下
傳回值型態 類別名稱::operator 運算子(參數)
{
  // Overloading程式碼
}

設計重載程式,必須注意"傳回值型態"。在任何的程式設計中,變數可能出現在等號的左邊或右邊,當位於左邊的時候,它代表一個位址,準備存放等號右邊運算式的運算結果(值);而當變數位於等號右邊的時候,它則要提供一個值。

Overloading 函式只能傳回一種型態,而索引 [] 運算又要滿足上述兩種可能,所以必須透過 reference (& 參考) 方式傳回。

結合 "Class template 類別樣版/模板" 與 Overloading [],class myData 改寫如下

#include <iostream>

template <typename dType>
class myData
{
//私有區段,只有class內部程式可存取
private:
   int _boundary; //陣列空間上限
   
//保護區段,只有class內部程式和繼承的class可存取
protected: 
   int len;  //資料總數 
   dType *data; //用來存放所有輸入資料的記憶空間指標
   dType errdata; 

//公用區段,class內外部程式均可存取
public:
   myData() //建構函式1,當物件產生時會自動執行(無參數) 
   {
      len=0; //資料長度歸0
      _boundary=10; //邊界設為10 
      data=new dType[_boundary]; //配置10個dType記憶空間 
   }
   
   myData(int n) //建構函式2,參數為陣列大小 
   {
      if(n<=0)
     myData(); //忽略錯誤參數,呼叫建構函式1 
      else
      { 
         len=n; //資料長度為n 
         _boundary=n; //邊界亦為n 
         data=new dType[n]; //配置n個dType記憶空間
          }
   }

   ~myData() //解構函式,當物件消滅時會自動執行
   {
      delete [] data; //釋放data記憶空間
   }
   
   dType& operator[](int n)
   {
      if (n>=len || n<0) //索引超過範圍
      { 
         std::cerr << "索引超過範圍:" << n << std::endl;
         return errdata; //回傳一個存在但無用的參考 
      }
      return data[n]; //ok,回傳 data[n] 的 reference 
   }

   void add(dType d)
   {
     if (len>=_boundary-1) //資料滿了,增加記憶空間
     {
       dType *nptr=new dType[_boundary+10]; //多配置10個dType記憶空間
       for(int i=0; i<len; i++)
         nptr[i]=data[i]; //把舊資料複製到新的位置
       delete [] data; //釋放舊的記憶空間
       data=nptr; //資料指標指向新的位置
       _boundary+=10;
     }
     data[len++]=d; //把參數d放在最後的位置後再把資料長度+1
   }
};

int main()
{
   myData<float> d(5); //宣告物件 d 有 5個 float 

   for(int i=0; i<7; i++) //故意超過範圍 
   { 
       d[i]=i/7.0; //d[i]是位址 
       std::cout << i/7.0 << std::endl; 
   }
   
   d.add(100); //再加一個元素到後面
  
   for(int i=0; i<7; i++) //故意超過範圍 
       std::cout << d[i] << std::endl; //d[i]是值  

   return 0;

}

現在以 myData 所宣告出來的物件已經可以如同陣列一樣的使用了,若再加上一些函式,可實現更自由的動態調節大小,以增加程式設計的彈性。

1 則留言:

  1. How to Play Casino: Easy Guide to playing slots on
    Casino games are played jancasino by 4 players, the average time they 출장마사지 take turns is around หาเงินออนไลน์ 14:20. The house https://tricktactoe.com/ is divided into three distinct categories: the gri-go.com house

    回覆刪除