
| 實習目標 |
operator overloading: operator->, operator*, operator[]
friend and Iterator static member variable |
|---|---|
| 步驟一 |
在上一個實習中我們製作了 Student 類別, StudentList 類別, StudentList::Node 類別, 這三個類別主要提供的功能包括將 Student 物件記錄在 StudentList 中, 將具有某一 id 的 Student 物件找到或是刪除。 還缺的功能包括
|
| 步驟二 |
我們先來看看測試程式, 了解希望加入的功能到底需要配合什麼應用程式:
void main()
{
StudentList sList;
sList.appendEntry(new Student("Mary Chen", "111111111",
"0933111111",
"Business"));
sList.appendEntry(new Student("John Wang", "222222222",
"0928222222",
"Computer Science"));
sList.appendEntry(new Student("Mel Lee", "333333333",
"0968333333",
"Mechanical Engineering"));
sList.appendEntry(new Student("Bob Tsai", "444444444",
"0930444444",
"Electrical Engineering"));
sList.appendEntry(new Student("Ron Yang", "555555555",
"0918555555",
"Computer Science"));
// 列印串列中所有的 Student 物件
int i;
Iterator iter(sList);
for (i=0, iter.reset(); iter.hasMoreData(); iter.next(), i++)
{
cout << i << ":";
iter->display(cout);
cout << endl;
}
cout << endl;
// 檢查是否串列中有兩個學生是在同一個系所的
Iterator iter1(sList), iter2(sList);
for (iter1.reset(); iter1.hasMoreData(); iter1.next())
{
for (iter2=iter1, iter2.next();
iter2.hasMoreData(); iter2.next())
{
if (iter1->ofTheSameDepartment(*iter2))
{
cout << "The following two students are "
"of the same department:\n";
iter1->display(cout);
cout << endl;
iter2->display(cout);
cout << endl;
}
}
}
// 在 id="333333333" 的學生之後再加入一個學生
for (iter1.reset(); iter1.hasMoreData(); iter1.next())
if (iter1->IDEquals("333333333"))
sList.insertEntry(iter1,
new Student("Carol Chen", "333331111",
"0933333111", "Business"));
for (i=0; i<sList.size(); i++)
sList[i]->display(cout);
}
|
| 步驟三 |
我們需要定義 Iterator 類別 這個類別依照上述的用法來看至少應該要有下列功能
class Iterator
{
public:
Iterator(StudentList &list);
void reset();
void next();
Student &operator*() const;
Student *operator->() const;
bool hasMoreData() const;
private:
StudentList::Node *m_iterator;
StudentList *m_list;
};
這個類別和 StudentList 有很密切的關連,
所以值得用 friend 功能來實作,
它需要存取 StudentList 內的資料成員,
所以需要在 StudentList 內將 Iterator 設為其 friend
建構元 Iterator(StudentList &list) 最主要需要建構出這個 Iterator 物件和 StudentList 之間的關係, 同時將 m_iterator 清為 0 reset() 及 next() 為移動目前的指標 m_iterator 位置的基本函式 hasMoreData() 測試是不是已經移到串列最尾端 operator->() 是一個 Smart pointer, 它應該要傳回目前指標 m_iterator 所指到的 Student 物件的指標, 例如:
Student *Iterator::operator->() const
{
if (m_iterator)
return m_iterator->m_data;
else
return 0;
}
operator*() 是 dereferencing operator, 它應該要傳回目前指標 m_iterator 所指到的 Student 物件的參考, 例如:
Student &Iterator::operator*() const
{
if (m_iterator)
return *(m_iterator->m_data);
else
return m_dummy;
}
m_dummy 是一個宣告在類別裡的 static Student 變數
class Iterator
{
...
private:
static Student m_dummy;
};
記得要在 iterator.cpp 中定義
Student Iterator::m_dummy;
|
| 步驟四 |
定義 int StudentList::size() const; 成員函式
傳回目前 StudentList 內 Student 物件的總個數, 這個函式內可以當場去算一遍到底 List 內有幾個節點, 也可以在 StudentList 內實作一個變數來記錄目前總共有幾筆資料, 在 appendEntry() 或是 insertEntry() 時加一, deleteEntry() 時減一 |
| 步驟五 |
定義 Student *&StudentList::operator[](int slot); 成員函式
將 List 中第 slot 個節點所記錄的 Student 物件的指標變數的參考傳回 |
| 步驟六 |
定義 void StudentList::insertEntry(Iterator iter, Student *student); 成員函式
請評估是否需要定義 Iterator 類別的拷貝建構元 要將一個 Student 物件加入目前 iter 所在的節點之後, Iterator 類別需要定義界面把它所記錄的節點傳出來, 或是 StudentList 可以將這個 insertEntry 的動作交給 Iterator 類別來完成 請注意由於 Iterator 類別定義時需要先定義 StudentList 類別, 因此在 Iterator.h 裡必須先 #include "StudentList.h"。但是此步驟中加入的成員函式使得定義 StudentList 時必須知道 Iterator 類別, 否則 compiler 會發出 "不認得 Iterator" 的錯誤訊息, 此時很直覺地就會希望在 StudentList.h 中加入 #include "Iterator.h" 的敘述, 以便在定義 StudentList 類別之前先定義 Iterator 類別, 可是這樣子做解決不了問題--你發現定義 StudentList 類別時希望先定義 Iterator 類別, 然後在定義 Iterator 類別時先定義 StudentList 類別 這兩個要求是矛盾的。 解決這個問題的方法是用 forward declaration (預先宣告) ----------------- Iterator.h --------------------
#include "StudentList.h"
class Iterator
{
...
};
---------------- Iterator.cpp -------------------
#include "Iterator.h"
...
--------------- StudentList.h ------------------
class Iterator;
class StudentList
{
...
};
-------------- StudentList.cpp -----------------
#include "StudentList.h"
#include "Iterator.h"
...
請注意
理論上另外一種可能的作法如下, 但是由於 class StudentList::Node; 是一個編譯器在 StudentList 為預先宣告類別時無法接受的敘述, 所以下面這個方式是不成功的 ----------------- Iterator.h --------------------
class StudentList;
class StudentList::Node;
class Iterator
{
...
};
---------------- Iterator.cpp -------------------
#include "Iterator.h"
#include "StudentList.h"
...
--------------- StudentList.h ------------------
#include "Iterator.h"
class StudentList
{
...
};
-------------- StudentList.cpp -----------------
#include "StudentList.h"
...
請注意一下一般來說 myClass.h 檔案內到底應該放些什麼東西?
最後在編譯你的程式時, 可以先點選個別 .cpp 檔案, 然後使用 建置/編譯 (Ctrl-F7) 來一個一個檔案確定語法以及所引入的檔案是否正確, 如果你使用 建置/建置方案 來編譯你的程式, 常常因為一次編譯多個檔案, 而且錯誤發生在引入的檔案中, 因為你的程式裡可能有很多地方都引入相同的檔案, 所以你弄不清楚到底是在編譯哪一個檔案時發生錯誤, 而誤導你的判斷 |
| 步驟七 |
定義 bool Student::ofTheSameDepartment(Student &student2); 成員函式
檢查兩個學生的系所是否相同 |
| 步驟八 |
請評估是否需要定義 Iterator::operator=() ?
請注意 Iterator 類別獨立於 StudentList 之外, 在使用時會有點奇怪, 這個 Iterator 類別只能和 StudentList 類別一起用, 也許叫做 StudentListIterator 比較恰當, 或者根本應該宣告在 StudentList 裡面作為一個 public inner class!! |
| 步驟九 |
請助教檢查後, 將所完成的 project (去掉 debug/ 資料匣下的所有內容) 壓縮起來, 選擇 Lab10-2 上傳, 後面的實習課程可能需要使用這裡所完成的程式 |

回
C++ 物件導向程式設計課程
首頁
製作日期: 05/04/2004
by 丁培毅 (Pei-yih Ting)
E-mail: pyting@mail.ntou.edu.tw
TEL: 02 24622192x6615
海洋大學
電機資訊學院
資訊工程系
Lagoon