11 類別化程式 11.1 結構與類別 結構與類別 結構化程式設計 結構化程式設計 物件導向程式設計 物件導向程式設計 程式類別 (class) 程式類別 (class) 宣告類別名稱 宣告類別名稱 類別資料成員 類別資料成員 類別成員函數 類別成員函數 建立類別物件 建立類別物件 存取類別成員 存取類別成員 建立者與破壞者 建立者與破壞者 建立者函數 (contructor) 建立者函數 (contructor) 宣告建立者參數 宣告建立者參數 預設建立者參數 破壞者函數 (destructor) 類別與指標 this 指標 物件陣列 類別與函數 const 物件與函數 friend 函數與類別 static 類別成員 傳遞物件參數 傳回類別資料 11-38
11.1 結構與類別 C 語言程式設計是以函數( function )為單元 的結構化程式設計。 C 語言程式設計是以函數( function )為單元 的結構化程式設計。 C++ 語言程式設計則是以類別( class )為單 元的物件導向程式設計。 C++ 語言程式設計則是以類別( class )為單 元的物件導向程式設計。 前一章討論的結構只能包含資料成員,而 類別從結構觀念衍生而可以包含資料成員 與成員函數,類別的資料變數稱為資料成 員( data member ),處理資料的函數稱為 成員函數( member function )。 前一章討論的結構只能包含資料成員,而 類別從結構觀念衍生而可以包含資料成員 與成員函數,類別的資料變數稱為資料成 員( data member ),處理資料的函數稱為 成員函數( member function )。
結構化程式設計 結構化程式設計( structure programming ) 或程序式程式設計( procedural program ) 是以程序(或稱函數)為主的程式。 結構化程式設計( structure programming ) 或程序式程式設計( procedural program ) 是以程序(或稱函數)為主的程式。 結構化程式的資料變數與存取資料的函數 是獨立的,通常函數提供處理資料變數的 運算。 結構化程式的資料變數與存取資料的函數 是獨立的,通常函數提供處理資料變數的 運算。
物件導向程式設計 物件導向程式設計( Object-Oriented Programming )是以類別物件為主的程式設 計。 物件導向程式設計( Object-Oriented Programming )是以類別物件為主的程式設 計。 類別的觀念是由結構衍生而來,結構只能 包含資料變數,而類別則可以包含資料變 數與處理資料的函數。 類別的觀念是由結構衍生而來,結構只能 包含資料變數,而類別則可以包含資料變 數與處理資料的函數。 類別中的資料變數稱為資料成員( data member ),處理資料的函數稱為成員函數 ( member function )。 類別中的資料變數稱為資料成員( data member ),處理資料的函數稱為成員函數 ( member function )。
物件導向程式設計 ( 續 )
11.2 程式類別( class ) 類別( class )是一種使用者自定的資料型 態,與結構一樣類別是由許多資料型態集 合而成。 類別( class )是一種使用者自定的資料型 態,與結構一樣類別是由許多資料型態集 合而成。 程式設計師可以在類別中定義多種資料型 態的變數,如 int 、 char 、 float 、或 string 等等, 這些資料變數稱為類別的資料成員( data member )。 程式設計師可以在類別中定義多種資料型 態的變數,如 int 、 char 、 float 、或 string 等等, 這些資料變數稱為類別的資料成員( data member )。 類別中還包括存取資料成員的函數稱為成 員函數( member function )。 類別中還包括存取資料成員的函數稱為成 員函數( member function )。
宣告類別名稱 class 類別名稱 { private: // 定義私用成員 public: // 定義公用成員 }; class 類別名稱 { private: // 定義私用成員 public: // 定義公用成員 };
宣告類別名稱 ( 續 ) 範例一 範例一 class Employee {private: // 類別私用成員 ; public: // 類別公用成員 ; }; 範例二 class Employee { // 類別私用成員 ; public: // 類別公用成員 ; };
類別資料成員 資料型態 變數名稱 ; 資料型態 變數名稱 ; 範例 範例 class Employee { int EmpId;// 定義 private 資料成員 char name[20]; // 定義 private 資料成員 public: // 類別公用成員 ; };
類別成員函數 傳回型態 函數名稱 ( 參數列 ) { // 敘述區 } 傳回型態 函數名稱 ( 參數列 ) { // 敘述區 } 範例 範例 class Employee { int EmpId;// 定義 private 資料成員 char name[20]; // 定義 private 資料成員 範例續 …… 範例續 ……
類別成員函數 ( 續 ) public: void inputEmp() {// 宣告 public 成員函數 cout << "EmpId:" << endl; cin >> EmpId; cout << "EmpName:" << endl; cin >> name; } void outputEmp() {// 宣告 public 成員函數 cout << "EmpId:" << EmpId << endl; cout << "EmpName:" << name << endl; }};
類別成員函數 ( 續 ) 傳回型態 類別名稱 :: 函數名稱 ( 參數列 ) { // 敘述區 } 傳回型態 類別名稱 :: 函數名稱 ( 參數列 ) { // 敘述區 } 範例 範例 class Employee { int EmpId;// 定義 private 資料成員 char name[20]; // 定義 private 資料成員 public: void inputEmp();// 宣告 public 成員函數原型 void outputEmp();// 宣告 public 成員函數原型 };
類別成員函數 ( 續 ) 範例續 範例續 void Employee::inputEmp() {// 定義 inputEmp 成員函數 cout << "EmpId:" << endl; cin >> EmpId; cout << "EmpName:" << endl; cin >> name; } void Employee::outputEmp() { // 定義 outputEmp 成員函數 cout << "EmpId:" << EmpId << endl; cout << "EmpName:" << name << endl; }
建立類別物件 類別名稱物件名稱 ; 類別名稱物件名稱 ; 範例 範例 int main() { Employee emp1;// 宣告 Employee 類別物件 return 0;// 程式正常結束 }
存取類別成員 物件名稱. 類別成員 () 物件名稱. 類別成員 () 範例 範例 int main() { Employee emp1; emp1.intputEmp();// 呼叫物件函數 inputEmp emp1.outputEmp();// 呼叫物件函數 outputEmp return 0;// 程式正常結束 }
Exercise 第 11 章習題第 1 題 第 11 章習題第 1 題 b) 先不作 b) 先不作
11.3 建立者與破壞者 建立者函數 (contructor) 建立者函數 (contructor) 宣告建立者參數 宣告建立者參數 預設建立者參數 預設建立者參數 破壞者函數 (destructor) 破壞者函數 (destructor)
建立者函數( constructor ) 類別名稱 ( 參數列 ) { // 建立者本體 } 類別名稱 ( 參數列 ) { // 建立者本體 }
建立者函數 ( 續 ) 範例一 範例一 class Employee { int EmpId;// 定義 private 資料成員 char name[20]; // 定義 private 資料成員 public: Employee() {// 定義無參數建立者函數 EmpId = 0;// 指定 EmpId 初值 strcpy(name, "ZZZ");// 指定 name 初值 }};
建立者函數 ( 續 ) 範例二 範例二 class Employee { int EmpId;// 定義 private 資料成員 char name[20]; // 定義 private 資料成員 public: Employee();// 宣告無參數建立者函數原型 }; Employee::Employee() {// 實現無參數建立者函數 EmpId = 0;// 指定 EmpId 初值 strcpy(name, "ZZZ");// 指定 name 初值 };
宣告建立者參數 類別名稱 ( 參數型態 參數 1, 參數型態 參數 2, … ) { // 建立者本體 } 類別名稱 ( 參數型態 參數 1, 參數型態 參數 2, … ) { // 建立者本體 } 範例一 範例一 class Employee { int EmpId;// 定義 private 資料成員 char name[20]; // 定義 private 資料成員 範例待續 … 範例待續 …
宣告建立者參數 ( 續 ) public: Employee(int id, char *n) {// 宣告建立者函數原型 EmpId = id;// 指定 EmpId= 參數值 strcpy(name, n);// 指定 name= 參數值 }}; int main() { Employee emp1(123, "TOM"); //emp1.EmpId=123,emp1.name="TOM" Employee emp2(456, "JOE"); //emp2.EmpId=456,emp2.name="JOE" return 0;// 程式正常結束 }
宣告建立者參數 ( 續 ) 範例二 範例二 class Employee { int EmpId;// 定義 private 資料成員 char name[20]; // 定義 private 資料成員 public: Employee(int id, char *n);// 宣告建立者原型 }; 範例二待續 …… 範例二待續 ……
宣告建立者參數 ( 續 ) Employee::Employee(int id, char *n) { // 定義有參數建立者 EmpId = id;// 指定 EmpId= 參數值 strcpy(name, n);// 指定 name= 參數值 }; int main() { Employee emp1(123, "TOM"); //emp1.EmpId=123,emp1.name="TOM" Employee emp2(456, "JOE"); //emp2.EmpId=456,emp2.name="JOE" return 0;// 程式正常結束 }
預設建立者參數 類別名稱 ( 參數型態 參數 1= 起始值 1, 參數型態 參數 2= 起始 值 2, … ) { // 建立者本體 } 類別名稱 ( 參數型態 參數 1= 起始值 1, 參數型態 參數 2= 起始 值 2, … ) { // 建立者本體 } 範例 範例 class Employee { int EmpId;// 定義 private 資料成員 char name[20]; // 定義 private 資料成員 public: Employee(int id, char *n);// 宣告建立者函數原型 };// 待續 ……
預設建立者參數 ( 續 ) Employee::Employee(int id = 0, char *n = "ZZZ") { EmpId = id;// 指定 EmpId 初值 strcpy(name, n);// 指定 name 初值 }; int main() { Employee emp1; Employee emp2(123, "TOM"); Employee emp3(456); return 0;// 程式正常結束 }
預設建立者參數 ( 續 ) 範例 ( 複製資料成員 ) 範例 ( 複製資料成員 ) int main() { Employee emp1(123, "JOHN"), emp2; emp2 = emp1;//emp2.EmpId=123 //emp2.name="JOHN" return 0;// 程式正常結束 }
破壞者函數( destructor ) ~ 類別名稱 () ~ 類別名稱 () 範例 範例 class Employee { int EmpId;// 定義 private 資料成員 char name[20];// 定義 private 資料成員 public: Employee();// 宣告建立者函數 ~Employee();// 宣告破壞者函數 };
Exercise 完成第 11 章習題第 1 題 完成第 11 章習題第 1 題
11.4 類別與指標 建立類別物件時,每個物件就有自己的指 標稱為 this ,所以在類別本體可以使用 this 指 標存取同一類別的資料成員。 建立類別物件時,每個物件就有自己的指 標稱為 this ,所以在類別本體可以使用 this 指 標存取同一類別的資料成員。 this-> 資料成員 // 指向資料成員位址 (*this). 資料成員 // 指向資料成員位址 this-> 資料成員 // 指向資料成員位址 (*this). 資料成員 // 指向資料成員位址
this 指標 範例 範例 class Employee { int EmpId; char name[20]; public: Employee() {// 定義建立者函數 EmpId = 0;// 指定 EmpId 初值 strcpy(name, "ZZZ");// 指定 name 初值 } void outputEmp() { cout EmpId EmpId << endl; // 取 Employee 指標的 EmpId cout << (*this).name << endl; // 取得 Employee 指標的 name }};
例: #include class A{ int y; public: A(){ y=0; } void showy(int z){ cout << "y = " << y << endl; } }; void main(){ A a1; a1.showy(1); }
物件陣列 類別名稱 陣列名稱 [ 陣列長度 ]; 類別名稱 陣列名稱 [ 陣列長度 ]; 範例 範例 class Number{// 宣告 Number 類別 int num;//Number 成員變數 public: void setNumber(void) {// 輸入圖書資料函數 cout << " 請輸入整數: "; cin >> num;// 輸入 num 成員資料 } void showNumber() {// 輸出圖書資料函數 cout << num << '\t';// 輸出 num 資料 }};
物件陣列 ( 續 ) 範例續 範例續 int main() { Number n[3]; // 建立 Number 型態陣列 for(int i=0; i<3; i++) {// 輸入 Number 資料迴圈 n[i].setNumber();// 呼叫物件 setNumber 函數 } cout << " 輸入三個整數為: "; for(int j=0; j<3; j++) {// 輸出圖書資料迴圈 n[j].showNumber();// 呼叫物件 showNumber 函數 } cout << endl; return 0; }
11.5 類別與函數 本節討論類別的一些特殊函數,如 const 、 friend 、 static 函數。 const 可宣告物件或函數 是固定不可被更改的; friend 宣告類別或函 數為公用的,且其他類別的函數皆可以使 用或呼叫此 friend 類別或函數; static 宣告資 料成員或成員函數為靜態的,也就是使用 同一類別建立的物件都共用同一個 static 資 料成員或成員函數。 本節討論類別的一些特殊函數,如 const 、 friend 、 static 函數。 const 可宣告物件或函數 是固定不可被更改的; friend 宣告類別或函 數為公用的,且其他類別的函數皆可以使 用或呼叫此 friend 類別或函數; static 宣告資 料成員或成員函數為靜態的,也就是使用 同一類別建立的物件都共用同一個 static 資 料成員或成員函數。
const 物件與函數 const 類別名稱物件名稱 ( 參數列 ); const 類別名稱物件名稱 ( 參數列 ); 範例 範例 class Employee { int EmpId; char name[20]; public: Employee(int e, char n[])// 定義建立者函數 { EmpId = e;// 指定 EmpId 初值 strcpy(name, n);// 指定 name 初值 }
const 物件與函數 ( 續 ) 範例續 範例續 void outputEmp() {// 宣告函數 outputEmp() cout EmpId EmpId << endl; // 顯示 EmpId 值 cout << (*this).name << endl; // 顯示 name 值 }}; int main() { const Employee emp1(123, "JOHN");//emp1 為常數物件 emp1.outputEmp();// 錯誤,Non-const function call return 0;// 程式正常結束 } 課本 有誤
const 物件與函數 ( 續 ) 函數型態 函數名稱 ( 參數列 ) const { // 函數本體 } 函數型態 函數名稱 ( 參數列 ) const { // 函數本體 } 範例 範例 class Employee { int EmpId; char name[20]; public: Employee(int e, char n[]) {// 定義建立者函數 EmpId = e;// 指定 EmpId 初值 strcpy(name, n);// 指定 name 初值 }
const 物件與函數 ( 續 ) 範例 範例 void outputEmp() const {// 宣告常數函數 outputEmp() cout EmpId EmpId << endl; // 顯示 EmpId 值 cout << (*this).name << endl; // 顯示 name 值 }}; int main() { Employee emp1(123, "JOHN");//emp1 為常數物件 emp1.outputEmp();// 呼叫常數函數 outputEmp() return 0;// 程式正常結束 }
friend 函數與類別 friend 函數型態 函數名稱 ( 參數列 ) { 敘述區 ; } friend 函數型態 函數名稱 ( 參數列 ) { 敘述區 ; } class 類別 B { friend class 類別 A; }; class 類別 B { friend class 類別 A; };
friend 函數與類別 ( 續 ) 範例 範例 class First { int x; public: friend int getx(First obj)// 定義 friend 函數 } return obj.x; }}; 範例待續 …… 範例待續 ……
friend 函數與類別 ( 續 ) 範例續 範例續 class Second { int y; public: void showxy(First obj) { cout << "x = " << getx(obj) << endl; // 呼叫 friend 函數 cout << "y = " << y << endl; }};
static 類別成員 static 資料型態 變數名稱 ;// 第一式 static 資料型態 變數名稱 ;// 第一式 static 函數型態 函數名稱 ( 參數列 ) { 敘述區 ; }// 第二式 static 函數型態 函數名稱 ( 參數列 ) { 敘述區 ; }// 第二式 範例 範例 class Oddsum { static int sum;// 宣告靜態資料成員 public: static void addition(int n);// 宣告靜態成員函數 }; 範例待續 …… 範例待續 ……
static 類別成員 ( 續 ) 範例續 範例續 int Oddsum::sum = 0;// 起始靜態資料成員 void Oddsum::addition(int n) {// 定義靜態成員函數 sum += n;//sum(n+1)=sum(n)+n } int main() { Oddsum A; for (int count = 1; count <= 100; count += 2) A.addition(count);// 呼叫 addition 函數 return 0;// 程式正常結束 }
Exercise 建立一個 employee 類別 建立一個 employee 類別 employee 類別的資料成員 employee 類別的資料成員 id: 整數變數,用以紀錄員工編號 id: 整數變數,用以紀錄員工編號 name: 字串變數,長度 20 ,用以紀錄員工名字 name: 字串變數,長度 20 ,用以紀錄員工名字 total: 整數變數,用來紀錄員工總數 total: 整數變數,用來紀錄員工總數 employee 類別的成員函數 employee 類別的成員函數 set: 參數有兩個,分別用來設定 id 及 name 之值 set: 參數有兩個,分別用來設定 id 及 name 之值 show: 列出員工編號及名字 show: 列出員工編號及名字 寫一個 main 函數 寫一個 main 函數 宣告一個 employee 類別的陣列物件 宣告一個 employee 類別的陣列物件 寫一個迴圈可以讓 user 輸入員工名字以新增員工,呼叫 員工物件的 set 函數,並在每一次輸入完成後,問 user 是 否繼續新增員工資料 寫一個迴圈可以讓 user 輸入員工名字以新增員工,呼叫 員工物件的 set 函數,並在每一次輸入完成後,問 user 是 否繼續新增員工資料 輸入結束後,利用 total 成員函數顯示員工總數,呼叫 show 成員函數列出所有員工的編號及名字 輸入結束後,利用 total 成員函數顯示員工總數,呼叫 show 成員函數列出所有員工的編號及名字
傳遞物件參數 函數型態 函數名稱 ( 類別名稱 參數名稱 ) { // 函數本體 } 函數型態 函數名稱 ( 類別名稱 參數名稱 ) { // 函數本體 } 物件名稱. 類別成員 ( 物件參數 )// 呼叫成員函數 物件名稱. 類別成員 ( 物件參數 )// 呼叫成員函數 範例 範例 class Calculate { int x; public: Calculate(int n) { x = n; }// 建立者函數
傳遞物件參數 ( 續 ) 範例續 範例續 void sum(Calculate obj) {// 加法運算, 傳遞物件參數 x += obj.x;//x = x + obj.x }}; int main() { Calculate a(100), b(200);// 定義 a.x=100, b.x=200 a.sum(b);// 計算 a.x = a.x + b.x return 0;// 程式正常結束 }
傳遞物件參數 ( 續 ) 函數型態 函數名稱 ( 類別名稱 * 參數名稱 ) { // 函數本體 } 函數型態 函數名稱 ( 類別名稱 * 參數名稱 ) { // 函數本體 } 物件名稱. 類別成員 (& 物件參數 )// 呼叫成員函數 物件名稱. 類別成員 (& 物件參數 )// 呼叫成員函數 範例 範例 class Calculate { int x; public: Calculate(int n) { x = n; }// 建立者函數
傳遞物件參數 ( 續 ) 範例續 範例續 void sum(Calculate *obj) {// 加法運算, 傳遞物件參數 x += obj->x;//x = x + obj.x }}; int main() { Calculate a(100), b(200);// 定義 a.x=100, b.x=200 a.sum(&b);// 計算 a.x = a.x + b.x return 0;// 程式正常結束 }
傳回類別資料 類別名稱 函數名稱 ( 參數列 ) { // 函數本體 return 類別物件名稱 ; } 類別名稱 函數名稱 ( 參數列 ) { // 函數本體 return 類別物件名稱 ; } 範例 範例 class Calculate { int x; public: Calculate(int n) { x = n; }// 建立者函數
傳回類別資料 ( 續 ) 範例續 範例續 Calculate calcSum(Calculate obj) {// 加法運算 x += obj.x;//x = x + obj.x return *this;// 傳回 (*this).x }}; int main() { Calculate a(100), b(200), c(0);// 定義 a.x=100, b.x=200 c = a.calcSum(b);// 計算 c.x = a.x + b.x return 0;// 程式正常結束 }
傳回類別資料 ( 續 ) 類別名稱 * 函數名稱 ( 參數列 ) { // 函數本體 return 類別物件指標 ; } 類別名稱 * 函數名稱 ( 參數列 ) { // 函數本體 return 類別物件指標 ; } 範例 範例 class Calculate { int x; public: Calculate(int n) { x = n; }// 建立者函數
傳回類別資料 ( 續 ) 範例續 範例續 Calculate *calcSum(Calculate obj) {// 加法運算 x += obj.x;//x = x + obj.x return this;// 傳回 this->x }}; int main() { Calculate a(100), b(200), c(0);// 定義 a.x=100, b.x=200 c = *(a.calcSum(b));// 計算 c.x = a.x + b.x return 0;// 程式正常結束 }
Homework 1 課本第 11 章習題第 2 題。 課本第 11 章習題第 2 題。
例 續…續…
例 續…續…
例 續…續…
例 續…續…
例 續…續…
例 續…續…
例
Homework 2 Book 類別 Book 類別 資料成員:書號、書名、是否在館內 資料成員:書號、書名、是否在館內 成員函數:設定書資料 成員函數:設定書資料 BookDataBase 類別 BookDataBase 類別 資料成員:書陣列 資料成員:書陣列 成員函數:新增書 成員函數:新增書 Student 類別 Student 類別 資料成員:學號、名字、可借書數量、已借數量 資料成員:學號、名字、可借書數量、已借數量 成員函數:設定學生資料 成員函數:設定學生資料 StudentDataBase 類別 StudentDataBase 類別 資料成員:學生陣列 資料成員:學生陣列 成員函數:新增學生 成員函數:新增學生 Record 類別 Record 類別 資料成員:書號、學號、借或還 資料成員:書號、學號、借或還 成員函數:設定紀錄資料 成員函數:設定紀錄資料 RecordDataBase 類別 RecordDataBase 類別 資料成員:紀錄陣列 資料成員:紀錄陣列 成員函數:新增紀錄 成員函數:新增紀錄 寫一個 main() ,列出 Menu ,讓使用者可以選擇新增書、新增學生、借書、還書等功能 寫一個 main() ,列出 Menu ,讓使用者可以選擇新增書、新增學生、借書、還書等功能