1 / 46

繼承 ( Inheritance)

繼承 ( Inheritance). 前言. 利用繼承的觀念, 可擴充舊的程式 為目前所須要的狀態 繼承舊的資料型態  定義出新的資料型態 新資料型態同時擁有 舊 的資料型態 method & data 新 的 method & data 新資料型態亦 可繼續被繼承. 基礎類別與衍生類別. 在物件導向程設中,被繼承的類別稱為 基礎類別 ( base class) 由繼承關係所定義出來的類別稱為 衍生類別 ( derived class). 基礎類別. 衍生類別. 馬上看看繼承的範例. 直接使用繼承而來的資料. 基礎類別下的資料隱藏.

glenna
Download Presentation

繼承 ( Inheritance)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 繼承 (Inheritance)

  2. 前言 • 利用繼承的觀念,可擴充舊的程式為目前所須要的狀態 • 繼承舊的資料型態定義出新的資料型態 • 新資料型態同時擁有 • 舊的資料型態 method & data • 新的method & data • 新資料型態亦可繼續被繼承

  3. 基礎類別與衍生類別 • 在物件導向程設中,被繼承的類別稱為基礎類別 (base class) • 由繼承關係所定義出來的類別稱為衍生類別 (derived class) 基礎類別 衍生類別 馬上看看繼承的範例

  4. 直接使用繼承而來的資料 基礎類別下的資料隱藏 如果已經寫好一個Based類別 class Based { private: int Mydata; protected: int Mydata2; public: Based() { Mydata=1234; Mydata2=5678; } }; 如何有效的重複使用過去的程式 我們使用繼承 class Derived : publicBased { public: Derived() { Mydata2++; } };

  5. private 封裝的資料 基礎類別下的資料隱藏 • private中的資料成員與成員函數 • 只可被該類別的成員函數使用 (不具備繼承的性質) • protected中的資料成員與成員函數 • 可被自己使用 • 亦可被衍生類別使用. (具備繼承的性質) • 別人不能使用 (資料隱藏) example example 驗證看看 NEXT

  6. private 封裝的資料 add(){ } Add 可以存取自己範圍內 的 private Data Private 成員存取範例 class Complex{ private: double Real; double Img; public: Complex(...); void add( int ConstValue){ Real+=ConstValue; Img+=ConstValue; } }; BACK

  7. class 動物{ 吃(); 喝(); } 基本的行為寫在 基礎類別 特別物種的行為寫在 衍生類別 class 人類{ 玩( ); 樂( ); } class 貓{ 洗臉( ); } 使用繼承的時機 (1/2) • 首先要把工作分類 • General Case • Special Case (基礎類別) (衍生類別)

  8. 使用繼承的時機 (2/2) • 情況: 學生成績 • 基礎類別只記錄共同科目的成積, • 對於某科系而言,還有專業科目 • 怎麼辦 ? • 直接修改基礎類別 • 或利用繼承的方法,設計衍生類別 • 不必動到基礎類別的任何程式碼 • 資源可以重複利用

  9. 資工系::衍生類別 class Computer:public Com { public: int AI; Computer() { AI=0; } }; 繼承的範例 共同科目::基礎類別 已經寫好處理共同科目程式 class Com { protected: int Chinese; int English; public : Com() { Chinese=0; English=0; } void SetGrade(int Chinese,int English) { this->Chinese=Chinese; this->English=English; } }; 利用繼承,加入人工智慧科目 加入新的科目

  10. 公用的基礎類別 繼承的語法 定義衍生類別的格式如下: class 衍生類別名稱:public基礎類別 { … }; • 繼承的方式 • public指明了基礎類別=>公用的基礎類別 • 亦可用 private指明基礎類別 為一私用基礎類別

  11. 私用的基礎類別 衍生類別的定義方法 • 當使用者沒有指明 private 或 public時: • 則內定為 private, 因此類別定義可以寫成 class Chemistry: ComFinal { … }; class Chemistry: private ComFinal { … }; 或

  12. 繼承的方式公用基礎類別VS 私用基礎類別 • public基礎類別: • 到自己的public區與protected區 • private 基礎類別: • 到自己的private區 基礎類別 衍生類別 private 區 private 區 protected 區 protected 區 基礎類別 衍生類別 public 區 public 區 private 區 private 區 Public方式繼承 protected 區 protected 區 public 區 public 區 看看圖示 Private方式繼承

  13. 繼承的方式公用基礎類別VS 私用基礎類別 • 不論是public或private基礎類別 • 其private區中的所有資料成員與成員函式都不可被繼承. 繼承的方式 資料隱藏與繼承的關係 基礎類別public基礎類別 private基礎類別 public public private protected protected private private 無法繼承無法繼承 Based Class 資料成員的存取屬性 該資料成員在Derived 中的存取屬性 該資料成員在Derived 中的存取屬性

  14. 繼承的方式公用基礎類別VS 私用基礎類別 • 例如 衍生類別B以 private的方式繼承了基礎類別A,則A的所有可繼承的成員都變成了衍生類別B的private成員 • 這使得基礎類別失去了 再被繼承的性質 基礎類別 A private 衍生類別 B public or private 衍生類別 C 無法由 A 繼承 任何成員

  15. 繼承的方式公用基礎類別VS 私用基礎類別 • 如果使用者希望一個基礎類別可以不斷的被衍生類別所繼承下去,則必須都設定為public 基礎類別 基礎類別 A public 衍生類別 B public 繼承A中非private 成員 衍生類別 C …. 衍生類別 Z

  16. 衍生類別之資料成員與成員函式的定義 • 在繼承關係下 • 只有public區與protected的資料成員與成員函式,可以被繼承. • 衍生類別只須定義新加入的成員, • 無法繼承的成員 • private區的所有成員 • Based 的建構子 class Base int weight; class Cat int sleep();

  17. 存在! 但不能直接存取. • 你可以用公共介面存取私用成員 • 宣告為 private 的成員,不能被繼承. 表示那些成員不存在於衍生物件中 ???

  18. Base class 建構子 ( 1 ) 建構子 ( 2 ) 建構子 ( 3 ) 意思是說 想要使用 建構子(2)來initial 基礎類別的資料成員, 怎麼辦?? ? Derived class 基礎類別 有許多建構自己的方法 好了, 現在我要用 指定的建構子建構基礎類別!

  19. class Based{ public: Based() {} }; class Derived:public Based{ public: Derived(){ } }; 使用基礎類別的預設建構子 指定要執行的 基礎類別的建構子 衍生類別的建構子 注意:用冒號 在繼承下衍生類別之Constructor的設計 • 呼叫基礎類別的建構子 • 忽略不寫. [預設建構子] 2. 由衍生類別的初值列中呼叫 [ 指定建構子] Chemistry:: Chemistry( …) : ComFinal( …)

  20. 在衍生類別中呼叫 Base class的constructor 範例 class Base { public: int basedata; Base(int data) { basedata=data; } }; class Derived:publicBase { public: int Derdata; Derived(int data): Base(data), Derdata(123){ } }; 建構子的初值列 基礎類別建構子 初值列設定初值

  21. 範例 class Base{ protected: int a,b,c; public: Base(int x=0,int y=0, int z=0); }; 衍生類別之constructor的進一步討論---Constructor 的呼叫順序 • Ok! 哪一個建構子先被執行? • 先執行基礎類別constructor • 而解構子,則相反

  22. 衍生類別之constructor的進一步討論---Constructor 的呼叫順序 Derived.h Class Derived: public Base { protected: int d,e; public: Derived(int x,int y,int z,int o,int p); }; Derived::Derived(int x,int y,int z,int o,int p): Base(x,y,z) { … } Derived.cpp 2 1

  23. 衍生類別之constructor的進一步討論--忽略呼叫基礎類別constructor的情況衍生類別之constructor的進一步討論--忽略呼叫基礎類別constructor的情況 • 若忽略在衍生類別的成員初設串列 • 衍生類別會呼叫基礎類別的 預設建構子 class point{ protected: int x,y; public: point(int a, int b=0); point() {x=0 ; y=0;} } 沒有參數的建構子 就是預設建構子

  24. line 繼承 point class line: public point { protected: int len; pulbic: line(int a,int b, int len); line(int len); line(); }; line::line(int a,int b, int l) : point(a,b) // line 的constructor { len=l; } line:: line(int l) { len=l; } Line 類別有兩個建構子 指定呼叫兩個參數的建構子 1 2 沒指定,則呼叫預設的建構子

  25. 如何使用繼承而來的成員 class Errormessage{ protected: char ** mes; int hmes; public:char * get_error_message(); }; 基礎類別 使用ShowError呼叫 class ShowError: public Errormessage{ public: int line; void show_error(const char * prompt) { } }; 衍生類別 ShowError Obj; Obj.get_error_message(); Obj.hmes++; 可直接呼叫 get_error_message(); 或 使用 hmes 變數 外界不能直接存取 Protected成員

  26. 內部自己的method 公用介面 如何使用繼承而來的成員 • Show_error 可以直接使用由基礎類別繼承而來的成員函數 • get_error_message() • 亦可使用物件來使用繼承而來的成員函數 例如 Showerror Error(error,0,5); Error.get_error_message(); • 即藉由衍生類別 Showerror的物件可以 • 使用自身定義的成員函數,也可用繼承而來的成員函數

  27. 好了, 現在我要更改 繼承而來的物件行為. 如何做??? Overriding(覆寫) member

  28. class Derived:public Based{ public: int data; void Run() { 做其他的運算 Ok(); } }; Overriding(覆寫) member • 衍生類別與基礎類別成員的名稱 • 相同 修改Run(),其他的不變 class Based{ public: int data; void Run() { 原來的版本 OK(); } void Ok() { … } };

  29. 不執行Based 的Run() 3 2 1 class Based{ public: int data; void Run() { 原來的版本 OK(); } void Ok() { … } }; 基礎類別 class Derived:public Based{ public: int data; void Run() { 做其他的運算 Ok(); } }; 衍生類別 DerObj-> Run(); 繼續執行

  30. Overriding(覆寫) member • 被隱藏不代表消失,它們仍舊是衍生類別的一部份,透過明確的範圍指定,依舊可以存取到這些成員 • Dclass.Base:: showID() 明確指定呼叫 Base 的 function 看一下範例

  31. 使用範例 class Errormessage { … void show(); … }; class showerror: public Errormessage{ … void show(const char * prompt); … }; void showerror::show(const char *prompt) { … Errormessage::show(); … } 基礎類別 衍生類別 明確指定呼叫 Errormessage的 show()

  32. Overriding Vs Overloading function • Overrinding function 乃指在衍生類別中重新定義基礎類別中已存在的函數名稱 • 只要 name相同,則基礎類別就會被隱藏,無論函數參數或傳回值是否一樣 • Ex: OverridingDemo.cpp • Overloading function乃指在同一有效範圍內,兩個函數可以有相同名稱與傳回值,只要其函數的參數相異即可.

  33. 類別中的friend沒有被繼承的性質 • 只有類別成員才能被繼承!! • Friend 並非類別成員,因此不會被衍生類別所繼承.

  34. 擴展你的程式-1 • 以上次繼承結果為這次繼承的資源 • 用繼承來撰寫物件程式的優點就是程式可依使用者須求加以擴充 • 繼承可以不斷的衍生下去 • 任何衍生類別都可成為下次繼承的基礎類別 Base class Base { }; class Derived : public Base{ }; class Third : public Derived { }; Derived Third …

  35. 擴展你的程式-2 • 設計衍生類別的constructor時,不必考慮為其祖先做設定的動作 • 衍生類別只須對上一層基礎類別負責即可 程式執行的順序 類別Base Base :: Base(…) Derived::Derived(…) Three::Three(…) 由Derived負責Based Constructor 類別 Derived 由Three負責Derived Constructor 類別 Third

  36. 我聽說C++有 多重繼承 的功能 這到底是怎麼回事???

  37. 多重繼承 • 情況: • 有兩個類別,其中一類別為 Circle用來畫各種圓形,另一類別為 Line用來畫各種線形圖形 • 現在設計者希望能提供一個圓柱類別 Cylinder,該類別應有畫圓與畫線的功能. • 我們希望能同時繼承 Circle 與 Line,這樣就可以充份利用原程式的資源

  38. A base class . . . class Line A base class . . . class Circle 繼 承 繼 承 Cylinder 所有衍生類別同時繼承circle 與 Line

  39. 多重繼承 --程式碼範例 class A{ … }; class B{ … }; 類別 C若欲同時繼承 A 與 B 則其表示方法為: class C: public A ,public B { … }; 加入逗號即可

  40. 多重繼承 --可能的錯誤 考慮下面Code: 並不表示A與B同時為 public基礎類別,事實上,B為private基礎類別. • 若沒有明確指定,則內定值為 private class C: public A, B{ … }

  41. 多重繼承 --基礎類別的constructors設定 • 衍生類別的constructor必須考慮到其繼承類別初設的必要引數量 • class Pay : public Sal, public Pro{ … }; • Inline Pay::Pay(char* n,int Id, int per, int wr): Sal(per), Pro(n,Id) { … } 明確指定呼叫 Sal的 某個建構子 明確指定呼叫 Pro 的 某個建構子

  42. 多重繼承 --constructor呼叫的順序 • 呼叫基礎類別constructor的順序決定於當時定義衍生類別時,指明的基礎類別順序 • Class Pay: public Sal, public Pro { { … }; • Inline Pay::Pay(char* n,int Id, int per, int wr): Sal(per), Pro(n,Id) 2 1 順序對換其初設順序亦不影響

  43. 多重繼承 --模擬兩可 • 考慮下面的 Code • 基礎類別A,B同時有相同名稱的成員函數show,而類別C繼承了 A , B class A{ … public: void show(); … }; class B{ … public: void show(); … };

  44. 多重繼承 --模擬兩可 class C: public A, public B { … }; 則 void main() { C cc; cc.show(); //呼叫那一個show()? }

  45. 多重繼承 --模擬兩可 • 衍生類別 C中有兩份同名稱的show成員函數,一份來自 A, 一份來自B, Compiler 無法判斷應該呼叫那一個show function. • 解決方法: • 利用範圍運算子指明欲呼叫的成員是屬於哪一個類別 C *obj=new C(); obj-> A:: show(); obj-> B:: show(); 明確指定呼叫A的show()

  46. End 井民全 debut.cis.nctu.edu.tw/~ching

More Related