實習目標 | 練習依照 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