610 likes | 747 Views
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
E N D
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 繼承類別
13.1 繼承概論 • 繼承(inheritance)的功能讓程式可以重複使用。例如,建立新類別時,使用繼承功能去吸收已存在類別的特性與功能到新類別中,如此可以節省許多程式開發的時間,所以繼承是處理複雜程式很有效率的技術。
13.1.1 基礎類別與衍生類別 • 當建立新類別時,使用繼承功能去繼承已存在類別的資料成員與成員函數,來取代重新撰寫新的資料成員與新的成員函數。 • 這已存在的類別稱為基礎類別(base class)或父類別(parent class),而新建立的類別稱為衍生類別(derived class)或子類別(child class)。 • 在衍生類別中可以新增自己的資料成員與成員函數,將來衍生類別也可能成為新建類別的基礎類別。
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.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: 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() { Derived d(10); //c = 10 d.set(2,3); //a=2, b=3 d.show(); //顯示2與3 d.showc(); //顯示10 }
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類別 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() { 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 保護型態的繼承 (續) • 建立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類別 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() { 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 多層類別繼承 (續) 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類別 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類別 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 多層類別繼承 (續) • 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 多重類別繼承 (續) • 建立Base1類別 Class Base1 { protected: int x; public: void showx() {cout << x << endl;} }; Base1
13.3.2 多重類別繼承 (續) • 建立Base2類別 Class Base2 { protected: int y; public: void showy() {cout << y << endl;} }; 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() { 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 • 類別Base1 • 私有資料成員:value1 • 公有成員函數:getValue1, setValue1 • 類別Base2 • 私有資料成員:value2 • 公有成員函數:getValue2, setValue2 • 建立類別Derived繼承Base1及Base2 • 公有成員函數: • 兩個參數之建立者函數:設定value1及value2的值 • Show:印出value1及value2的值
13.4 建立者與破壞者 • 建立衍生類別物件時,會先呼叫基礎類別的建立者,再呼叫衍生類別的建立者。而結束衍生類別物件時,則以相反順序先呼叫衍生類別的破壞者,再呼叫基礎類別的破壞者。也就是先建立者後破壞(first-construct-last-destruct)。
13.4.1 單一建立者與破壞者 (續) • 建立Base類別 class Base { public: Base() {cout << "建立基礎類別\n";} ~Base() {cout << "破壞基礎類別\n";} };
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 多層建立者與破壞者 (續) • 建立Base類別 class Base { public: Base() {cout << "建立基礎類別\n";} ~Base() {cout << "破壞基礎類別\n";} };
13.4.2 多層建立者與破壞者 (續) • 是建立Derived1類別,並以public型態繼承Base類別 class Derived1: public Base { public: Derived1() {cout << "建立衍生類別\n";} ~Derived1() {cout << "破壞衍生類別\n";} };
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 多重建立者與破壞者 (續) • 建立Base1類別 class Base1 { public: Base1() {cout << "建立基礎類別1\n";} ~Base1() {cout << "破壞基礎類別1\n";} };
13.4.3 多重建立者與破壞者 (續) • 建立Base2類別 class Base2 { public: Base2() {cout << "建立基礎類別2\n";} ~Base2() {cout << "破壞基礎類別2\n";} };
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: Base(int x) {i = x;} };
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成員。