1.23k likes | 1.47k Views
最新 C & C++ 學習範本. 第 14 章 物件與類別. 本章投影片僅供本書上課 教師 使用 , 非經同意請勿拷貝或轉載. 14-1 物件的基本觀念. 一、什麼是物件 (Object) 物件 就是東西、物件就是物體,例如人是物件、車子是物件、電腦也是物件;而在程式設計領域中所謂的物件,則是使用程式技巧模擬真實世界物件而得的程式碼與資料。一般都將物件分成以下三部份來處理: 1. 屬性 (Property) 2. 方法 (Method) 3. 訊息 (Message) 或事件 (Event). P14-2. 二、什麼是屬性 (Property).
E N D
最新C & C++學習範本 第14章 物件與類別 本章投影片僅供本書上課教師使用,非經同意請勿拷貝或轉載
14-1 物件的基本觀念 一、什麼是物件 (Object)物件 就是東西、物件就是物體,例如人是物件、車子是物件、電腦也是物件;而在程式設計領域中所謂的物件,則是使用程式技巧模擬真實世界物件而得的程式碼與資料。一般都將物件分成以下三部份來處理: 1. 屬性(Property)2. 方法(Method)3. 訊息(Message)或事件(Event) P14-2
二、什麼是屬性 (Property) 電腦程式設計領域,將上述這些特徵與狀態一律稱為屬性,物件的屬性也會直接或間接影響物件本身的一些特質: • 物件的屬性決定了物件的基本特徵與所表現出來的行為模式,例如體重(屬性) 200公斤的人跑(行為)得就比體重60公斤的人慢。 • 相同物件的屬性可以是不相同的。例如一樣是人,有些人身高(屬性) 比較高,有些人則比較矮;有些人是黑髮(屬性)、有些人是金髮。 • 物件的屬性可以由物件自行改變。例如人會自己長高、變老。物件的屬性也可以由外界來改變。例如經由染髮將髮色由黑色變為金色、做皮下抽脂使體重下降。 • 相同種類的物件中,個別物件可以有自己特有的屬性。例如少數人有特異功能、而一般人就沒有。 P14-2
三、方法(Method) • 物件的方法就是物件可執行的動作。 • 物件的方法在執行上的差異往往取決於物件的屬性。 P14-3
四、什麼是訊息(Message)和事件(Event) • 如果物件只有屬性與方法,那物件只不過是獨立個體,而無法與外界其它物件相聯繫,因此物件必須要能收發 訊息。 • 訊息(Message)或事件Event)就是物件與物件之間用來溝通彼此的訊號、語言等等。 • 要發送、接收與處理訊息,必須藉由 物件的方法來執行,例如聽(方法)話(訊息)。 • 將這類專門用來處理訊息的方法,叫做「事件程序」。 P14-3
五、屬性、方法與訊息的關係 • 物件的方法就是物件對外界的溝通界面 • 物件的屬性就是決定物件特性的內部資訊 • 物件與物件間溝通,是經由訊息的傳遞來達成: P14-4
六、什麼是類別(Class) • 類別就是類似物件的集合。例如 ”人” 這個類別包含天下所有的人。 • 類別只是將這些類似物件的屬性、方法、訊息加以整理,用來描述這些類似的物件,因此 類別並不是實際的物件。類別是物件的定義。 • 例如下圖小明、小娟、小華都是人,都是實際存在的物件,有自己的屬性與方法。 P14-4
從程式設計觀點,類別只是一種資料型態,而物件則屬於該種資料型態的實體變數從程式設計觀點,類別只是一種資料型態,而物件則屬於該種資料型態的實體變數 • 如C++ 的int 可看做整數類別,但卻無法直接用 int 類別來做加減運算(方法) • 如下面程式片斷: int a ; int b ; a = 12 ; b = a + 5 ; int = 32 ; P14-5
由上面程式片斷,類別可用來宣告產生物件,但本身卻不是物件,也不可用來執行。類別要如何衍生成物件呢?下圖是類別與物件的關係圖:由上面程式片斷,類別可用來宣告產生物件,但本身卻不是物件,也不可用來執行。類別要如何衍生成物件呢?下圖是類別與物件的關係圖: P14-5
七、物件的特性 • 抽象化(Abstraction) • 封裝(Encapsulation) • 繼承(Inheritance) • 多形(Polymorphism) • 動態繫結(Dynamic binding) P14-6
1.抽象化(Abstraction) • 思考物件時,是以抽象概念來進行,而不是以物件實體來思考。 • 一般高階語言都可將變數抽象化,例如將變數total_money 看做總金額來做處理,而不是以變數a、b這種無意義方式進行資料處理。 • 在物件導向程式設計,更將抽象性擴展到物件上,程式設計者可針對 car(汽車)物件進行處理 • 如用 Car.Weight 取得汽車的重量 用 Car.Start 啟動汽車而不用函式觀點來處理相關程序,例如用GetWeight(Car)函式來取得汽車的重量用Startup(Car)函式來啟動汽車。 P14-6
2. 封裝(Encapsulation) • 物件或多或少都有屬於物件內部的私有部份(屬性、方法…),這些部份必須是外界無法直接接觸,才能保有物件的完整性。 • 物件必須將私有部份封裝在物件內部,使用者只能藉由物件所提供方法、屬性來操作物件,以保持物件完整性。 • 將資料結構和用來操作該資料結構的所有方法,包裝在物件的類別定義中。外界無法直接存取該物件內部的資料,僅能透過物件開放的存取介面來進行存取,可保證物件完整性。 P14-7
3. 繼承(Inheritance) • 物件有繼承特性,就可不用完全重新製做一個新物件。 • 以往結構化程式設計,程式設計者如要對原來程式庫做功能增減,就需修改原始碼或重新撰寫程式庫。 • 在物件導向程式設計中,程式設計者只要重新設計一個新的物件類別,並繼承舊有的物件類別,就可在不更動舊有程式庫情況下,增減物件功能。 P14-8
4. 多形(Polymorphism) • 物件相同的動作卻造就出不同結果,叫做多形(Polymorphism)。 • 多形所指的就是物件的相同方法在不同個體(Instance)的執行過程與結果不同的性質。 • 物件有多形的特性,可簡化很多物件處理過程。程式執行時會根據不同物件,選擇適當的物件程序來執行。 • 可用同樣敘述執行不同物件中的相同方法,就叫做多型 (Polymorphism) • 如何能達成多型的特性,這就是另一個物件導向程式的特性:動態繫結(Dynamic binding)。 P14-8
5. 動態繫結(Dynamic binding) • 一般呼叫物件方法有兩種方法與物件的繫結方式一種是靜態繫結 Static binding(又稱早期繫結Early binding),一種是動態繫結Dynamic binding (又稱後期繫結 Late binding)。 • 靜態繫結指的是編譯器在程式編譯階段,就將物件與方法繫結在一起,如將 A.DoIt 直接編譯成機器碼,直接呼叫 A物件的 DoIt方法。 • 動態繫結指的是編譯器在程式編譯的階段並不將物件與方法繫結在一起,而是將物件方法函式的位址製作成一個虛擬表格(virtual table),在執行階段時,再由虛擬表格中判斷該呼叫那個物件方法函式 • 如執行 A.DoIt 時,先判斷 A.DoIt 是那一種物件的 DoIt 方法,在虛擬表格中找到該方法函式的位址,進行函式呼叫,可做到物件多型(Polymorphism)。 P14-10
14-2 類別的定義 • 類別(Class)就是結構(Structure)的延伸 • 傳統C 結構(Structure)只能有資料項目(或稱欄位)。 • C++ 的類別是由資料成員(Data Member) 和成員函式(Member Function) 組成。 • 類別主要任務就是把資料和相關函式封裝起來,告訴電腦此物件含有那些資料成員與成員函式,外界欲存取物件內的屬性,必須透過成員函式達到資料封裝的特性。 P14-10
1. 定義類別 class classname { private: data1; 資料成員(Data member) function1; 成員函式(Member function) public: data1; 資料成員(Data member) function1; 成員函式(Member function) } ; //分號表示定義到此結束 2. 宣告物件 classname objectname ; //產生一個名稱為objectname的物件, //它是屬於classname類別的一個物件
//FileName:createclass.cpp 01 #include <cstdlib> 02 #include <iostream> 03 #include <iomanip> 04 #include <string> 05 06 using namespace std; 07 08 class book 09 { 10 private: 11 string bookid, bookname; 12 int qty, price, total; 13 public: 14 void setbookinfo(string _bookid, string _bookname, int _price, int _qty) 15 { 16 bookid=_bookid; 17 bookname=_bookname; 18 price=_price; 19 qty=_qty; 20 total=qty*price; 21 }
22 void getbookinfo() 23 { 24 cout << "以下是你訂書的資訊:" << endl 25 << "書號:" << bookid << endl 26 << "書名:" << bookname << endl 27 << "單價:" << price << endl 28 << "數量:" << qty << endl 29 << "總金額:" << total << endl ; 30 } 31 int orderbooktotal() 32 { 33 return total; 34 } 35 36 }; 37 int main(int argc, char *argv[]) 38 { 39 book vb, csharp; 40 system("PAUSE"); 41 return EXIT_SUCCESS; 42 }
14-3 資料成員的初值設定與存取 • 當用一般資料型態宣告一個變數,C++ 允許在宣告同時設定該變數初值。 • 定義類別時,資料成員是不允許同時設定初值,必須透過成員函式或 Constructor(物件建構者) 來設定資料成員的初值。 • 程式中欲存取資料成員內容時,必須透過 物件名稱.成員函式名稱敘述來完成,以滿足物件本身的封裝性。 P14-16
//FileName:datamember1.cpp 01 #include <cstdlib> 02 #include <iostream> 03 #include <iomanip> 04 #include <string> 06 using namespace std; 07 class book { 09 private: 10 string bookid, bookname; 11 int qty, price, total; 12 public: 13 void setbookinfo(string _bookid, string _bookname, int _price, int _qty) { 15 bookid=_bookid; 16 bookname=_bookname; 17 price=_price; 18 qty=_qty; 19 total=qty*price; 20 } 21 void getbookinfo() { 23 cout << "以下是你訂書的資訊:" << endl 24 << "書號:" << bookid << endl 25 << "書名:" << bookname << endl 26 << "單價:" << price << endl 27 << "數量:" << qty << endl 28 << "總金額:" << total << endl ; 29 }
30 int orderbooktotal() 31 { 32 return total; 33 } 34 }; 35 36 int main(int argc, char *argv[]) 37 { 38 book vb, csharp; 39 40 vb.setbookinfo("7205167", "Visual Basic 2008學習範本", 690, 40); 42 vb.getbookinfo(); 44 cout << endl << "再次檢視總金額為-->" << vb.orderbooktotal(); 45 cout << endl << endl << "-----------------------" << endl << endl; 46 47 csharp.setbookinfo("7205207", "Visual C# 2008學習範本", 650, 29); 48 49 csharp.getbookinfo(); 50 51 cout << endl << "再次檢視總金額為-->" << csharp.orderbooktotal() << "\n\n"; 53 system("PAUSE"); 54 return EXIT_SUCCESS; 55 }
// FileName : datamember2.cpp 01 #include <cstdlib> 02 #include <iostream> 03 #include <iomanip> 04 #include <string> 05 06 using namespace std; 07 class book 08 { 09 private: 10 string bookid, bookname; 11 int qty, price, total; 12 public: 13 void setbookinfo(string _bookid, string _bookname, int _price, int _qty); 14 void getbookinfo(); 15 int orderbooktotal(); 16 }; P14-19
17 void book::setbookinfo(string _bookid, string _bookname, int _price, int _qty) 18 { 19 bookid=_bookid; 20 bookname=_bookname; 21 price=_price; 22 qty=_qty; 23 total=qty*price; 24 } 25 void book::getbookinfo() 26 { 27 cout << "以下是你訂書的資訊:" << endl 28 << "書號:" << bookid << endl 29 << "書名:" << bookname << endl 30 << "單價:" << price << endl 31 << "數量:" << qty << endl 32 << "總金額:" << total << endl ; 33 } 34 int book::orderbooktotal() 35 { 36 return total; 37 } 38
39 int main(int argc, char *argv[]) 40 { 41 book vb, csharp; 42 43 vb.setbookinfo("7205167", "Visual Basic 2008學習範本", 690, 40); 44 45 vb.getbookinfo(); 46 47 cout << endl << "再次檢視總金額為-->" << vb.orderbooktotal(); 48 cout << endl << endl << "-----------------------" << endl << endl; 49 50 csharp.setbookinfo("7205207", "Visual C# 2008學習範本", 650, 29); 51 52 csharp.getbookinfo(); 53 54 cout << endl << "再次檢視總金額為-->" << csharp.orderbooktotal() << "\n\n"; 55 56 system("PAUSE"); 57 return EXIT_SUCCESS; 58 }
14-4 類別陣列與類別指標 • 結構內所定義資料欄位都屬於 public • 類別中所定義資料成員存取模式可為 private、public或protected。 • 類別陣列的使用時機是當同類別中需要使用多個物件,為免去對物件名稱命名困擾,使用陣列註標代替各個物件名稱,方便物件間資的處理,語法: 一、類別陣列 class classname //定義類別{ };classnameobjectname[arraysize]; //宣告類別陣列 P14-21
// FileName : classarray.cpp 01 #include <cstdlib> 02 #include <iostream> 03 #include <iomanip> 04 #include <string> 05 06 using namespace std; 07 class grade 08 { 09 private : 10 int bcc, math, eng; float avg; 11 public : 12 void set(); 13 void display(); 14 }; 15 void grade::set() 16 { 17 cout << " 計概成績:"; 18 cin >> bcc; 19 cout << " 數學成績:"; 20 cin >> math; 21 cout << " 英文成績:"; 22 cin >> eng; 23 avg=(float)(bcc+math+eng)/3; 24}
25 void grade::display() 26 { 27 cout << " 計概:" << bcc; 28 cout << " 數學:" << math; 29 cout << " 英文:" << eng ; 30 cout << " 平均:" << avg; 31 } 32 33 int main(int argc, char *argv[]) 34 { 35 grade my[4]; 36 37 for(int k=1;k<=3;k++) 38 { 39 cout << "輸入" << k << "號同學的成績" << endl; 40 my[k].set(); 41 } 42 cout << endl << "-----------------------------------------------\n\n"; 43 for(int i=1;i<=3;i++) 44 { 45 cout << endl << i << "號同學的成績-->" ; 46 my[i].display(); 47 } 48 cout << "\n\n"; 49 system("PAUSE"); 50 return EXIT_SUCCESS; 51 }
二、類別指標 • 類別指標的宣告方式和結構指標是一樣的,先宣告一個指向該類別的指標變數及一個類別陣列,再將該指標變數指向該類別陣列 • 語法: class classname{ }; classname objectname; classname *ptr; ptr = &objectname; P14-24
// FileName : classpointer.cpp 01 #include <cstdlib> 02 #include <iostream> 03 #include <iomanip> 04 #include <string> 05 06 using namespace std; 07 class grade 08 { 09 private : 10 int bcc, math, eng; float avg; 11 public : 12 void set(); 13 void display(); 14 };
15 void grade::set() //由鍵盤輸入三科的成績放入資料成員 • 16 { • 17 cout << " 計概成績:"; • 18 cin >> bcc; • 19 cout << " 數學成績:"; • 20 cin >> math; • 21 cout << " 英文成績:"; • 22 cin >> eng; • 23 avg=(float)(bcc+math+eng)/3; • 24} • 25 void grade::display() • 26 { • 27 cout << " 計概:" << bcc; • 28 cout << " 數學:" << math; • 29 cout << " 英文:" << eng ; • 30 cout << " 平均:" << avg; • 31 } • 32
33 int main(int argc, char *argv[]) 34 { 35 36 grade my[4]; 37 grade *ptr; 38 ptr=my; 39 40 for(int k=1;k<=3;k++) 41 { 42 cout << "輸入" << k << "號同學的成績" << endl; 43 44 (ptr+k)->set(); 45 } 46 cout << endl << "-----------------------------------------------\n\n"; 47 for(int i=1;i<=3;i++) 48 { 49 cout << endl << i << "號同學的成績-->" ; 50 (ptr+i)->display(); 51 } 52 cout << "\n\n"; 53 system("PAUSE"); 54 return EXIT_SUCCESS; 55 }
14-5 物件間引數的傳遞 • 函式間資料的傳遞是靠著引數來做傳遞工作 • 引數資料型態除一般資料型態:int、float、double、char、string、struct外,也可為類別資料型態 • 可將物件當作引數來做資料傳遞。 P14-27
// FileName : classargsend.cpp 01 #include <cstdlib> 02 #include <iostream> 03 #include <iomanip> 04 #include <string>. 05 06 using namespace std; 07 class TPerson 08 { 09 private: 10 int tall; 11 int weight; 12 public : 13 void set(int, int); 14 int ShowTall(); 15 int ShowWeight(); 16}; 17 void TPerson::set(int _tall, int _weight) 18 { 19 tall=_tall; 20 weight=_weight; 21 } 22 int TPerson::ShowTall() 23 { 24 return tall; 25 }
26 int maxTall(TPerson a, TPerson b 27 { 28 29 if(a.ShowTall() > b.ShowTall()) 30 return 1; 31 else 32 return 0; 33} 34 35 int main(int argc, char *argv[]) 36 { 37 int flag; 38 TPerson tom, mary; 39 tom.set(175, 70); 40 mary.set(165, 55); 41 flag=maxTall(tom, mary); 42 if(flag==1) 43 cout << "Tom 比 Mary 高 !!"; 44 else 45 cout << "Mary 比 Tom 高 !!"; 46 cout << "\n\n"; 47 system("PAUSE"); 48 return EXIT_SUCCESS; 49 }
14-6 Constructor 與 Destructor 函式 一、Constructor函式 • C++ 允許使用一個建構者函式 (Constructor Function)含入到類別的定義中(通常此函式名稱和類別名稱同名) • 當該類別依照定義產生(建立)物件時,該類別建構子(Constructor) 就被呼叫,並藉由此 Constructor 函式為新產生的物件分配主記體空間以及為資料成員設定初值。 • 程式設計階段沒有將 Constructor 放入到所定義類別內,Compiler 自動提供一個不做事的預設 Constructor 函式稱為「Default Constructor」也會配置一個記憶體空間給此類別所產生的物件使用,但未做初始化的工作。 P14-29
在 C++中一個類別是允許擁有一個以上的Constructor函式。 • 設計程式時只要Constructor函式的引數個數及引數的資料型態不相同,C++編譯器會將這些Constructor 函式視為不同Constructor函式。 • 由於 Constructor 有此特性,可透過 Constructor函式來對資料成員做各種不同方式的初值設定。
對 TRec 類別定義三個不同的 Constructor函式 一個是Default Constructor一個是用來設定一個資料 成員的初值 一個是用來設定所有資料 成員的初值: P14-30
// FileName : constructor.cpp 01 #include <cstdlib> 02 #include <iostream> 03 #include <iomanip> 04 #include <string> 05 06 using namespace std; 07 class TRec 08 { 09 private : 10 int length; 11 int width; 12 public : 13 TRec() 14 {length=width=0 ;} 15 TRec(int _length) 16 {length=width=_length ;} 17 TRec(int _length, int _width) 18 {length=_length; width=_width ;} 19 int disp() 20 {return length*width ;} 21 }; 22
23 int main(int argc, char *argv[]) 24 { 25 cout << " 建構者函式給不同初值求面績\n\n" ; 26 TRec a; 27 cout << " TRec a() 未給初值-->" << a.disp() << "\n\n"; 28 29 TRec b(10); 30 cout << " TRec b(10) 給一個初值-->" << b.disp() << "\n\n"; 31 32 TRec c(10, 20); 33 cout << " TRec c(10, 20)給兩個初值-->" << c.disp() << "\n\n"; 34 35 system("PAUSE"); 36 return EXIT_SUCCESS; 37 }
二、Destructor函式 • 物件離開有效範圍不再使用(也就是說生命期結束),會自動呼叫 解構者(Destructor)將該物件所佔用的記憶體空間釋放掉。 • 有關 Destructor 函式的宣告方式和 Constructor函式類似,兩者必須使用類別名稱當其函式名稱而且兩者都不允許傳回值,因此無須宣告其傳回值型態; • 差別 Destructor 不允許有引數而且名稱的前面要加上『~』波浪符號,不像 Constructor函式能擁有多個定義函式,Destructor 只能有一個函式, P14-33
下面定義 TPerson 類別的 Destructor 函式寫法:~TPerson() { }。 01 Class TPerson 02 { 03 private: 04 int tall; 05 int weight; 06 public: 07 TPerson() { }; 08 TPerson(int ,int); 09 ~TPerson() { } 10 }; 11 TPerson::TPerson(int _tall, int _weight) 12 { 13 tall=_tall; 14 weight=_weight; 15 } 16 int main(int argc, char *argv[]) 17 { 18 TPerson david[10]; 19 }