Lab 6-2: Coding the UML spcification
   ctor and dtor practicing

 
實習目標 練習依照 UML 的類別圖實作類別, 製作類別間靜態的連結, 練習撰寫建構元與解構元
 
步驟一 請參考下面 UML 的類別圖, 製作所需要的類別

這是一個描述類似海洋大學這樣子的組織的課程資訊系統, 主要針對所有開設的課程來描述相關的組織架構, 首先學校裡面有好幾個學院, 每一個學院裡面又有不同的系所, 每一個系所每個學期都會開設許多的課程, 系所也有許多的老師, 每個課程都有一個老師在負責授課。

在這個實習中我們針對紅色的部份來製作, 下一個實習中我們實作整個架構, 也探討這個架構有什麼樣的問題存在

步驟二 請定義 University, College 和 Department 這三個類別, 其中的資料部份先用你覺得最方便的型態, 例如 m_name 可以用 string 類別或是字元陣列 char [] 來實作, 所有類別內的資料成員基本上都是 private 的
步驟三 接下來要建構類別間的關係, 例如我們學校裡有四個學院, 所以在 University 類別中要有一個容器物件, m_colleges, 你可以用 vector<College> 來製作, 如此在 University 解構時, 所有的 m_colleges 也都會一起解構; 如果考量效率的話, 你也可以用 vector<College *> 來製作, 但是解構就需要自己寫了。

請注意, 如果你選擇使用 vector<College> 來製作, 你會發現 vector<College>::push_back(College) 函式會需要傳入一個 College 物件, 此時會呼叫所謂的拷貝建構元 (copy constructor) 來處理參數的拷貝, 目前我們還沒有談到拷貝建構元的寫法和使用的時機, 所以如果你要使用 vector<College> 來實作的話, 建議你其它所有的關係也都用 vector<Department>, vector<Institute>, vector<Teacher>, vector<Course> 來實作, 如此實作除了效率會造成一些小問題之外, 唯一真正的問題在於雙向的連結 (例如 Course - Teacher 間的連結)。

如果你覺得每個學校的學院變化不大, 不需要用 vector 那麼一般化的容器物件來製作, 你也可以像 3bags 程式那樣子用陣列來實作, 例如 College colleges[4]; 在 C++ 中你也可以選擇用指標陣列來實作, 如此可以省掉許多不必要的資料拷貝的動作, 例如 College *colleges[4]; 只是記得要在初始化 University 物件 時就透過 new 和 delete 來配置和釋放那些 College 物件的記憶體

在 College 中有 Department, 你可以用 vector<Department *> 來定義, 如此在解構 College 時, Department 不會自動被解構, 你可以自行掌握所有物件的生命週期

注意什麼時候用 vector, 什麼時候用 C/C++ 語法裡原本的陣列, 完全是效率和程式碼大小的考量, 你可以斟酌程式的複雜度, 可讀性和效率來使用

步驟四 接下來我們要定義建構元, 建構元主要將每一個資料成員適當地初始化, 資料成員除了狀態變數之外, 也應該包括架構物件間連結的所有資料, 所以上層物件 (例如 University 類別的物件) 的建構元執行完畢之後, 通常整個系統物件的架構都已經架起來了。 (因為它間接地會讓每一個物件的建構元都執行過。)

相對地解構元除了釋放自己類別內使用的記憶體外, 常常也會將整個物件架構摧毀。

有些建構元可以有預設的數值, 有些則需要在建構時將資料當做參數傳遞進去, 我們這個應用程式的資料量有點大, 如果為了兼顧彈性, 也不適合將所有資料物件用預設的方式建立起來, 所以我們打算由檔案串流中讀取資料。

步驟五

我們把資料放在 ntou1.txt 檔案內, 資料如下:

    海洋大學             // 學校名稱
    5                    // 學院個數
    生命與資源科學院     // 第一個學院名稱
    2                    // 此學院內學系個數
    食品科學系           // 第一個學系名稱
    水產養殖系           // 第二個學系名稱
    海運學院             // 第二個學院名稱
    3
    商船學系
    航運管理學系
    機械與輪機工程系
    理學院               // 第三個學院名稱
    1
    海洋科學系
    工學院               // 第四個學院名稱
    4
    電機工程學系
    資訊工程學系
    河海工程學系
    系統工程暨造船學系
    技術學院             // 第五個學院名稱
    3
    運輸技術系
    輪機工程系
    導航與通訊系
此檔案內每一筆資料代表意義以及讀取方法請參考 testRead1.cpp, 以及 testRead1.exe (請下載後執行)

請設計各個建構元函式, 依據此資料檔案內容建構各個物件, 例如: College 類別的建構元如下:

    College::College(ifstream &infile)
    {
        char buf[50];
        getline(infile, m_name, '\n'); // string m_name; 學院名稱

        int numberOfDepartments;
        infile >> numberOfDepartments;
        infile.getline(buf, 50, '\n');

        int iDept;
        for (iDept=0; iDept<numberOfDepartments; iDept++)
            m_departments.push_back(new Department(infile)); 
            // vector<Department *> m_departments;

    }
請注意, 由於在建構元中產生了這些 Department 物件, 所以在解構元中需要把它們釋放掉, 才不會有記憶體的遺失
    College::~College()
    {
        std::vector<Department *>::iterator iter;
        for (iter=m_departments.begin();
             iter<m_departments.end();
             iter++)
            delete *iter;
    }
步驟六 為了作基本的測試, 我們在 University, College, 和 Department 類別內都增加一個 print(ostream &) 的公開成員函式, 個自將自己類別的內容印出, 例如:
    void University::print(std::ostream &os)
    {
        os << "學校名稱:" << m_name << std::endl;
        std::vector<College *>::iterator iter;
        for (iter=m_colleges.begin();
             iter<m_colleges.end();
             iter++)
            (*iter)->print(os);
    }
注意 ostream 參數必須使用參考變數或是指標變數, 以避免解構全域串流物件
步驟七 你可以在 University 類別中寫一個 static 的成員函式來測試看看目前所寫的功能:
    void University::unitTest()
    {
        ifstream infile("ntou1.txt");
        if (!infile)
            std::cout << "Cannot open ntou1.txt!!\n";
        else
        {
            University ntou(infile);
            ntou.print(std::cout);
        }
    }
範例執行程式 campusCourse1.exe (請下載後執行)
步驟八 請助教檢查後, 將所完成的 project (去掉 debug/ 資料匣下的所有內容) 壓縮起來, 選擇 Lab6-2 上傳, 後面的實習課程可能需要使用這裡所完成的程式

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

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