Lab 7-1: Operator overloading II: type conversion operator and constructor

 
實習目標 練習定義型態轉換建構元型態轉換運算子
 
步驟一 這次實習接續實習 3: 複數類別, 請下載實習 3 所完成的 Complex 類別程式碼
步驟二 在類別裡原先我們設計了 Complex::setValue(double, double) 的成員函式來初始化每一個 Complex 物件, 請你將這個函式移除, 另外撰寫一個建構元函式
    Complex::Complex(double, double);
來取代 setValue() 函式的功能, 並且在程式其它地方完成必要的修改, 請檢查原先的測試程式是不是都正確地運作, 這個時候我們應該慶幸上一次在寫的時候寫了很多 assert 敘述, 這些敘述自動幫我們檢查修改過的程式是不是對的, 如果那時設計得好, 現在要用眼睛慢慢檢查的機會就小很多了。

不是說慢慢地檢查很不好, 而是你要檢查的話一定要把上一次的程式完整了解過才能檢查, 上一次設計時也許有一些設計的取捨也許你現在已經忘了, 這都是很容易在軟體裡產生 bug 的時機, 所以以前很多很有經驗的程式師, 都是死也不肯修改舊的程式的, 就算程式看起來很簡單, 他的經驗告訴他, 增加一點點的功能可能會增加很多的 bugs, 在沒有預防的情況下這的確是事實, 所以以往客戶永遠沒有辦法理解為什麼程式設計者那麼頑固, 明明是很小的功能也不肯直接去改...

步驟三 假設你宣告一個函式需要接受 Complex 類別的物件作為參數, 例如
    void Complex::addTwice(Complex data)
    {
        m_real += data.m_real * 2;
        m_imaginary += data.m_imaginary * 2;
    }
正常的呼叫方法如下
    Complex a(1,2), b(3,4);
    a.addTwice(b);
有沒有辦法讓下面的呼叫也正常運作呢?
    double c=10.0;
    a.addTwice(c);
在上面這個敘述中基本上希望將傳進去的實數 c 當成是實數部份把它加在複數 a 上, 一種方法是作出一個暫時性的 Complex 物件, 再傳入函式裡運算, 請自己先想一下怎麼寫, 再測試下面的程式:
    a.addTwice(CComplex(c, 0));
第二種方法就是我們要大家寫的型態轉換建構元了, 我們知道在下面的程式裡 Compiler 會自動幫我們轉換資料:
    double square(double x)
    {
        return x*x;
    }
    ...
    int z=10;
    double y;
    y = square(z);
int 型態的變數 z 裡面的資料會自動地轉換為 double 型態, 然後拷貝到變數 x 當中進行運算, 我們現在就是希望能夠有這種功能, 方法很簡單, 請定義一個建構元如下:
    Complex::Complex(double x)
        :m_real(x), m_imaginary(0.0)
    {
    }
然後再測試 a.addTwice(c); 的程式碼, 或是 a = 10.5; 應該都可以用了吧, 有了這個建構元, Compiler 就可以自動幫你由 double 型態建構出一個 Complex 類別的物件出來, 並且傳進函式中處理。

它看起來和一般的建構元沒有什麼差異, 不過也有人特別叫它型態轉換建構元 (type conversion operator)。

其實還有另外一種方法可以運用上一步驟的建構元 Complex::Complex(double,double) 來完成我們在這一步驟裡所作的轉換, 就是用函式預設的參數, 自己想一想囉! (請參考投影片 page8, 請注意預設的參數必須在類別的定義裡面設定, 不是在類別的實作裡設定)

步驟四 接下來我們來寫型態轉換運算子 (type conversion operator)

我們在 C 中會看到下列的強制型態轉換的程式片段:

    int x;
    double y=20.5;
    x = (int) y;
(int) 就是型態轉換的運算子, 在 C++ 中我們可以替某一個類別的物件定義一個型態轉換的運算子, 例如我們可以替 Complex 類別定義 (double) 的運算子, 將 Complex 類別的物件轉換為 double 型態的資料, 當然我們需要先界定這個轉換的意義到底是什麼, 假設我們把一個複數物件轉換成它的長度如下:
    Complex a(10.5, 20.3);
    double magnitude;
    magnitude = a;
如果沒有特別的定義, C++ compiler 會說上面這個敘述是錯的, 請定義下面的成員函式:
    Complex::operator double()
    {
        return sqrt(m_real*m_real+m_imaginary*m_imaginary);
    }
如此前面的轉換就可以順利進行了, 同時你也可以用下面兩種敘述:
    magnitude = (double) a;
    magnitude = double(a);
效果都是一樣的。 另外如果你有一個函式接受一個 double 型態的參數, 你現在也可以把一個 Complex 的物件傳進去, compiler 會自動幫你轉換。
步驟五 請助教檢查後, 將所完成的 專案 (只需保留 .cpp, .h, .sln 以及 .vcxproj 檔案即可; 刪除掉 .suo, .sdf, .filters, .users, debug\ 資料匣, 以及 ipch\ 資料匣下的所有內容)壓縮起來, 選擇 Lab7-1 上傳, 後面的實習課程可能需要使用這裡所完成的程式

C++ 物件導向程式設計課程 首頁

製作日期: 03/23/2013 by 丁培毅 (Pei-yih Ting)
E-mail: pyting@mail.ntou.edu.tw TEL: 02 24622192x6615
海洋大學 電機資訊學院 資訊工程學系 Lagoon