13 繼承類別 13.1 繼承概論 13-2 13.1.1 基礎類別與衍生類別 13-2 13.1.2 繼承型式 13-2 13 繼承類別 13.1 繼承概論 13-2 13.1.1 基礎類別與衍生類別 13-2 13.1.2 繼承型式 13-2 13.1.3 保護成員 13-2 13.2 單一類別繼承 13-3 13.2.1 公用型態的繼承 13-3 13.2.2 私用型態的繼承 13-7 13.2.3 保護型態的繼承 13-10 13.3 多重類別繼承 13-12 13.3.1 多層類別繼承 13-12 13.3.2 多重類別繼承 13-16 13.4 建立者與破壞者 13-19 13.4.1 單一建立者與破壞者 13-19 13.4.2 多層建立者與破壞者 13-21 13.4.3 多重建立者與破壞者 13-24 13.4.4 傳遞參數到基礎建立者 13-26 13.5 繼承與包含 13-28 13.5.1 繼承類別 13-29 13.5.2 包含類別 13-31
13.1 繼承概論 繼承(inheritance)的功能讓程式可以重複使用。例如,建立新類別時,使用繼承功能去吸收已存在類別的特性與功能到新類別中,如此可以節省許多程式開發的時間,所以繼承是處理複雜程式很有效率的技術。
13.1.1 基礎類別與衍生類別 當建立新類別時,使用繼承功能去繼承已存在類別的資料成員與成員函數,來取代重新撰寫新的資料成員與新的成員函數。 這已存在的類別稱為基礎類別(base class)或父類別(parent class),而新建立的類別稱為衍生類別(derived class)或子類別(child class)。 在衍生類別中可以新增自己的資料成員與成員函數,將來衍生類別也可能成為新建類別的基礎類別。
13.1.2 繼承型式 C++ 提供公用(public)、私用(private)與保護(protected)三種繼承型式。 13.1.2 繼承型式 C++ 提供公用(public)、私用(private)與保護(protected)三種繼承型式。 在public繼承型式中,衍生類別只能存取基礎類別中public與protected的成員,而不能直接存取基礎類別中private的成員,但可透過基礎類別中public與protected的成員函數間接存取基礎類別的private成員。
13.1.3 保護成員 存取基礎類別的protected 成員的,則是介於存取public與private成員之間,基礎類別的protected成員可被基礎類別與衍生類別的成員函數與friend函數所存取。 所以對於衍生類別的成員函數而言,可以直接使用public與protected成員名稱存取該資料成員。 而對於其他類別(非衍生類別)的成員函數而言,則不可直接存取protected與private資料成員,必須透過public成員函數來存取protected與private資料成員。
13.2 單一類別繼承
13.2.1 公用型態的繼承 class 衍生類別: public 基礎類別 基礎類別 衍生類別 其他類別 基礎類別成員型態 13.2.1 公用型態的繼承 class 衍生類別: public 基礎類別 基礎類別 衍生類別 其他類別 基礎類別成員型態 存取基礎類別成員 繼承後成員型態 存取衍生類別成員 private成員 (否) protected成員 (可) public成員
13.2.1 公用型態的繼承 (續) 建立基礎類別 class Base { int a, b; public: 13.2.1 公用型態的繼承 (續) 建立基礎類別 class Base { int a, b; public: void set(int n, int m) {a = n; b = m;} void show() {cout << a << " " << b << endl;} };
13.2.1 公用型態的繼承 (續) 建立衍生類別 class Derived: public Base { int c; public: 13.2.1 公用型態的繼承 (續) 建立衍生類別 class Derived: public Base { int c; public: Derived() {c = 0;} Derived(int n) {c = n;} void setc() {c = a * b;} //錯誤!不可直接存取a, b void showc() {cout << c;} };
13.2.1 公用型態的繼承 (續) Derived物件可以呼叫Base與Derived類別的public函數 int main() { 13.2.1 公用型態的繼承 (續) Derived物件可以呼叫Base與Derived類別的public函數 int main() { Derived d(10); //c = 10 d.set(2,3); //a=2, b=3 d.show(); //顯示2與3 d.showc(); //顯示10 }
13.2.2 私用型態的繼承 class 衍生類別: private 基礎類別 基礎類別 衍生類別 其他類別 基礎類別成員型態 13.2.2 私用型態的繼承 class 衍生類別: private 基礎類別 基礎類別 衍生類別 其他類別 基礎類別成員型態 存取基礎類別成員 繼承後成員型態 存取衍生類別成員 private成員 (否) protected成員 (可) public成員
13.2.2 私用型態的繼承 (續) 建立Base類別 class Base { protected: int a, b; public: 13.2.2 私用型態的繼承 (續) 建立Base類別 class Base { protected: int a, b; public: void set(int n, int m) {a = n; b = m;} void show() {cout << a << " " << b << endl;} };
13.2.2 私用型態的繼承 (續) Derived類別是以private型態繼承Base類別 13.2.2 私用型態的繼承 (續) Derived類別是以private型態繼承Base類別 class Derived: private Base { protected: int c; public: Derived(int num) {c = num;} void setab(int n, int m) { set(n, m); } //呼叫Base::set() void showab() {show();} //呼叫Base::show() void showc() {cout << c;} };
13.2.2 私用型態的繼承 (續) Derived物件只可以呼叫Derived類別的public函數 int main() { 13.2.2 私用型態的繼承 (續) Derived物件只可以呼叫Derived類別的public函數 int main() { Derived d(10); //c=10 d.set(20,30); //錯誤,不能直接呼叫set d.setab(20,30); //呼叫Derived的setab d.show(); //錯誤,不能直接呼叫show d.showab(); //呼叫Derived的showab d.showc(); //呼叫Derived的showc return 0; //正常結束程式 }
13.2.3 保護型態的繼承 class 衍生類別: protected 基礎類別 基礎類別 衍生類別 其他類別 基礎類別成員型態 13.2.3 保護型態的繼承 class 衍生類別: protected 基礎類別 基礎類別 衍生類別 其他類別 基礎類別成員型態 存取基礎類別成員 繼承後成員型態 存取衍生類別成員 private成員 (否) protected成員 (可) public成員
13.2.3 保護型態的繼承 (續) 建立Base類別 class Base { private: int a; protected: 13.2.3 保護型態的繼承 (續) 建立Base類別 class Base { private: int a; protected: int b; public: int c; void seta(int n) {a = n;} void geta() {return a;} };
13.2.3 保護型態的繼承 (續) Derived類別是以protected型態繼承Base類別 13.2.3 保護型態的繼承 (續) Derived類別是以protected型態繼承Base類別 class Derived:protected Base { public: void setb(int n) {b = n;} //可直接設定protected值 int getb() {return b;} //可直接取得protected值 void setc(int n) {c = n;} //可直接設定public值 int getc() {return c;} //可直接取得public值 void seta1(int n) {seta(n);} //呼叫seta()間接設定a值 void geta1() {geta();} //呼叫geta()間接取得a值 };
13.2.3 保護型態的繼承 (續) Derived物件只可以呼叫Derived類別的public函數 int main() { 13.2.3 保護型態的繼承 (續) Derived物件只可以呼叫Derived類別的public函數 int main() { Derived d; d.seta(20); //錯,不可呼叫Base的公用函數 d.seta1(20); //呼叫Derived的公用函數 cout << d.geta(); //錯,不可呼叫Base的公用函數 cout << d.geta1(); //呼叫Derived的公用函數 d.c = 10; //錯,不可存取Base的公用函數 d.setc(10); //c = 10 cout << d.getc(); //顯示10 return 0; //正常結束程式 }
13.3 多重類別繼承 多重繼承的狹義定義是衍生類別直接繼承了多個基礎類別如13.3.2節的多重繼承,而多重繼承的廣義定義是衍生類別直接與間接繼承了多個基礎類別如13.3.1節的多層繼承與13.3.2節的多重繼承。
13.3.1 多層類別繼承
13.3.1 多層類別繼承 (續) 建立Base類別 Class Base { protected: int a, b; public: 13.3.1 多層類別繼承 (續) Base 建立Base類別 Class Base { protected: int a, b; public: void set(int n, int m) {a = n; b = m;} void show() {cout << a << " " << b << endl;} };
13.3.1 多層類別繼承 (續) Derived1類別以public型態繼承Base類別 13.3.1 多層類別繼承 (續) Derived1類別以public型態繼承Base類別 class Derived1: public Base { protected: int c; public: void setc() {c = a * b;} //直接取得Base的a, b void showc() {cout << c;} }; Base Derived1
13.3.1 多層類別繼承 (續) Derived2 類別以public型態繼承Derived1類別 13.3.1 多層類別繼承 (續) Derived2 類別以public型態繼承Derived1類別 class Derived2: public Derived1 { protected: int d; public: void setd() {d = a - b;} //直接取得Base的a, b void showd() {cout << d << endl;} }; Base Derived1 Derived2
13.3.1 多層類別繼承 (續) Base Derived1 Derived2 Derived1與Derived2物件 13.3.1 多層類別繼承 (續) Derived1與Derived2物件 int main() { Derived1 d1; Derived2 d2; d1.set(2,5); //a=2, b=5 d1.show(); //輸出2 5 d1.setc(); //c=a*b=2*5=10 d1.showc(); //輸出10 d2.set(3,4); //a=3, b=4 d2.show(); //輸出3 4 d2.setc(); //c=a*b=3*4=12 d2.showc(); //輸出12 d2.setd(); //d=a-b=3-4=-1 d2.showd(); //輸出-1 return 0; //正常結束程式 } Base Derived1 Derived2
13.3.2 多重類別繼承
13.3.2 多重類別繼承 (續) 建立Base1類別 Class Base1 { protected: int x; public: 13.3.2 多重類別繼承 (續) 建立Base1類別 Class Base1 { protected: int x; public: void showx() {cout << x << endl;} }; Base1
13.3.2 多重類別繼承 (續) 建立Base2類別 Class Base2 { protected: int y; public: 13.3.2 多重類別繼承 (續) 建立Base2類別 Class Base2 { protected: int y; public: void showy() {cout << y << endl;} }; Base2
13.3.2 多重類別繼承 (續) Derived類別以public型態繼承Base1與Base2類別 13.3.2 多重類別繼承 (續) Derived類別以public型態繼承Base1與Base2類別 class Derived: public Base1, public Base2 { public: void set(int i, int j) {x = i; y = j;} }; Base1 Base2 Derived
13.3.2 多重類別繼承 (續) Derived物件可以呼叫Base1與Base2類別的public函數 int main() { 13.3.2 多重類別繼承 (續) Derived物件可以呼叫Base1與Base2類別的public函數 int main() { Derived d; d.set(2,3); //設定x=2, y=3 d.showx(); //輸出x = 2 d.showy(); //輸出y = 3 return 0; //正常結束程式 } Base1 Base2 Derived
Exercise 下載EX1301.cpp 建立類別Derived繼承Base1及Base2 類別Base1 類別Base2 公有成員函數: 私有資料成員:value1 公有成員函數:getValue1, setValue1 類別Base2 私有資料成員:value2 公有成員函數:getValue2, setValue2 建立類別Derived繼承Base1及Base2 公有成員函數: 兩個參數之建立者函數:設定value1及value2的值 Show:印出value1及value2的值
13.4 建立者與破壞者 建立衍生類別物件時,會先呼叫基礎類別的建立者,再呼叫衍生類別的建立者。而結束衍生類別物件時,則以相反順序先呼叫衍生類別的破壞者,再呼叫基礎類別的破壞者。也就是先建立者後破壞(first-construct-last-destruct)。
13.4.1 單一建立者與破壞者
13.4.1 單一建立者與破壞者 (續) 建立Base類別 class Base { public: 13.4.1 單一建立者與破壞者 (續) 建立Base類別 class Base { public: Base() {cout << "建立基礎類別\n";} ~Base() {cout << "破壞基礎類別\n";} };
13.4.1 單一建立者與破壞者 (續) 建立Derived類別 class Derived: public Base { public: 13.4.1 單一建立者與破壞者 (續) 建立Derived類別 class Derived: public Base { public: Derived() {cout << "建立衍生類別\n";} ~Derived() {cout << "破壞衍生類別\n";} };
13.4.1 單一建立者與破壞者 (續) 建立Derived物件d時,先呼叫Base(建立者)函數再呼叫Derived(建立者)函數。而結束main函數時則先呼叫~Derived(破壞者)函數再呼叫~Base(破壞者)函數。 int main() { Derived d; return 0; //正常結束程式 }
13.4.2 多層建立者與破壞者
13.4.2 多層建立者與破壞者 (續) 建立Base類別 class Base { public: 13.4.2 多層建立者與破壞者 (續) 建立Base類別 class Base { public: Base() {cout << "建立基礎類別\n";} ~Base() {cout << "破壞基礎類別\n";} };
13.4.2 多層建立者與破壞者 (續) 是建立Derived1類別,並以public型態繼承Base類別 13.4.2 多層建立者與破壞者 (續) 是建立Derived1類別,並以public型態繼承Base類別 class Derived1: public Base { public: Derived1() {cout << "建立衍生類別\n";} ~Derived1() {cout << "破壞衍生類別\n";} };
13.4.2 多層建立者與破壞者 (續) 建立Derived2類別,並以public型態繼承Derived1類別 13.4.2 多層建立者與破壞者 (續) 建立Derived2類別,並以public型態繼承Derived1類別 class Derived2: public Derived1 { public: Derived2() {cout << "建立衍生類別2\n";} ~Derived2() {cout << "破壞衍生類別2\n";} };
13.4.2 多層建立者與破壞者 (續) 建立Derived2物件d時,先呼叫Base(建立者)函數,再呼叫Derived1(建立者)函數,最後呼叫Derived2(建立者)函數。而結束main函數時則先呼叫~Derived2(破壞者)函數,再呼叫~Derived1(破壞者)函數,最後呼叫~Base(破壞者)函數。 int main() { Derived2 d; return 0; //正常結束程式 }
13.4.3 多重建立者與破壞者
13.4.3 多重建立者與破壞者 (續) 建立Base1類別 class Base1 { public: 13.4.3 多重建立者與破壞者 (續) 建立Base1類別 class Base1 { public: Base1() {cout << "建立基礎類別1\n";} ~Base1() {cout << "破壞基礎類別1\n";} };
13.4.3 多重建立者與破壞者 (續) 建立Base2類別 class Base2 { public: 13.4.3 多重建立者與破壞者 (續) 建立Base2類別 class Base2 { public: Base2() {cout << "建立基礎類別2\n";} ~Base2() {cout << "破壞基礎類別2\n";} };
13.4.3 多重建立者與破壞者 (續) 建立Derived類別,並以public型態繼承Base1與Base2類別 13.4.3 多重建立者與破壞者 (續) 建立Derived類別,並以public型態繼承Base1與Base2類別 class Derived: public Base1, public Base2 { public: Derived() {cout << "建立衍生類別\n";} ~Derived() {cout << "破壞衍生類別\n";} };
13.4.3 多重建立者與破壞者 (續) 建立Derived物件d時,呼叫先繼承的Base1(建立者)函數,再呼叫後繼承的Base2(建立者)函數,最後呼叫Derived(建立者)函數。而結束main函數時則先呼叫~Derived(破壞者)函數,再呼叫~Base2(破壞者)函數,最後呼叫~Base1(破壞者)函數。 int main() { Derived d; return 0; //正常結束程式 }
13.4.4 傳遞參數到基礎建立者 建立Base類別 class Base { protected: int i; public: 13.4.4 傳遞參數到基礎建立者 建立Base類別 class Base { protected: int i; public: Base(int x) {i = x;} };
13.4.4 傳遞參數到基礎建立者 (續) 建立Derived類別,並宣告以public型態繼承Base類別 13.4.4 傳遞參數到基礎建立者 (續) 建立Derived類別,並宣告以public型態繼承Base類別 class Derived: public Base { protected: int j; public: Derived(int a, int b): Base(a) //i = 參數a {j = b;} //j = 參數b };
13.4.4 傳遞參數到基礎建立者 (續) 建立Derived物件d(10, 20) 時,參數a=10將被傳到Base類別,所以i = 10,而參數b=20則被指定給Derived的資料成員j。 int main() { Derived d(10,20); //i = 10, j = 20 return 0; //正常結束程式 }
exercise 下載書中光碟程式C1306.cpp及C1307.cpp 執行兩程式以了解多層繼承及多重繼承時建立者函數及破壞者函數之呼叫順序 改變C1307.cpp中,Derived類別多重繼承Base1及Base2類別的順序,看看建立者函數及破壞者函數之呼叫順序是否亦跟著變化
13.5 繼承與包含 繼承(inherence)的關係是建立在子類別(衍生類別)繼承父類別(基礎類別)的成員,繼承後子類別可直接存取父類別的public與protected成員。 包含(composition)的關係則是建立在母類別(包含類別)包含子類別(被包含類別)的物件,也就是在母類別中建立子類別的物件,然後利用子類別物件存取子類別的public成員。
13.5.1 繼承類別 建立Employee基礎類別 Class Employee { ptotected: char name[20]; 13.5.1 繼承類別 建立Employee基礎類別 Class Employee { ptotected: char name[20]; int idEmp; public: void setdata() { cin >> name; cin >> idEmp; } void getdata() { cout << name << endl; cout << idEmp << endl; } };
13.5.1 繼承類別 (續) Manager類別以public型態繼承Employee類別 13.5.1 繼承類別 (續) Manager類別以public型態繼承Employee類別 class Manager: public Employee { protected: char titles[20]; double bonus; public: void setdata() Employee::setdata(); //呼叫Employee的setdata cin >> titles; cin >> bonus; } };
13.5.1 繼承類別 (續) 建立Manager物件m後,以m物件呼叫Manager類別的setdata與Employee類別的getdata函數。 int main() { Manager m; m.setdata(); m.getdata(); return 0; //正常結束程式 }
13.5.2 包含類別
13.5.2 包含類別 (續) 建立Point類別 class Point //定義Point類別 { int x, y; public: 13.5.2 包含類別 (續) 建立Point類別 class Point //定義Point類別 { int x, y; public: int getx() const { return x; } int gety() const { return y; };
13.5.2 包含類別 (續) Square類別成員中包含Point類別的物件comP class Square //定義Square類別 13.5.2 包含類別 (續) Square類別成員中包含Point類別的物件comP class Square //定義Square類別 { public: Point comP; //包含Point物件 int getarea() const { return comP.getx() * comP.gety(); //呼叫Point的函數成員 } };
13.5.2 包含類別 (續) 建立Education基礎類別 class Education { protected: 13.5.2 包含類別 (續) 建立Education基礎類別 class Education { protected: char degree[20]; public: void setdata() { cin >> degree; } void getdata() { cout << degree << endl; };
13.5.2 包含類別 (續) 建立Employee基礎類別 Class Employee { protected: 13.5.2 包含類別 (續) 建立Employee基礎類別 Class Employee { protected: char name[20]; public: void setdata() { cin >> name; } void getdata() { cout << name << endl; };
13.5.2 包含類別 (續) 定義Manager類別並包含Employee類別物件emp與Education類別物件edu 13.5.2 包含類別 (續) 定義Manager類別並包含Employee類別物件emp與Education類別物件edu class Manager { protected: char title[20]; Employee emp; //包含Employee類別物件 Education edu; //包含Education類別物件 public: void setdata() { emp.setdata(); edu.setdata(); cin >> title; } void getdata() { emp.getdata(); edu.getdata(); cout << title; } };
13.5.2 包含類別 (續) 建立Manager物件m後,以m物件呼叫Manager類別的setdata與Employee類別的getdata函數。 int main() { Manager m; m.setdata(); //呼叫Manager的setdata m.getdata(); //呼叫Manager的getdata return 0; //正常結束程式 }
exercise 建立一個類別Vertex 建立一個類別Line 建立main函數 私有資料成員:int x, y 公有成員函數getX, setX, getY, setY 建立一個類別Line 私有資料成員:vertex beginVertex, endVertex 公有成員函數:getBeginVertex, setBeginVertex, getEndVertex, setEndVertex, calcLength 建立main函數 宣告vertex v1, v2 宣告Line l 設定v1及v2的x y座標值 設定l的兩個端點為v1及v2 印出l中兩端點座標及l的長度
Final 建立一個類別Vertex 建立一個類別Rectangle 建立main函數 私有資料成員:int x, y 公有成員函數getX, setX, getY, setY 建立一個類別Rectangle 私有資料成員:vertex beginVertex, endVertex 公有成員函數:getBeginVertex, setBeginVertex, getEndVertex, setEndVertex, calcarea 建立main函數 宣告vertex v1, v2, v3, v4 宣告Rectangle r 設定v1, v2, v3, v4的x y座標值 印出r的面積