--- GA: G-RZYLL0RZGV --- ###### tags: `大一程設-下` `東華大學` `東華大學資管系` `基本程式概念` `資管經驗分享` Inheritance 繼承 === [TOC] ## 前言 繼承是物件導向的重要特性之一,可以讓我們避免撰寫不必要的程式,<span style="color:red">**在往下閱讀之前,請務必先閱讀以下的參考資料。**</span> * [C++ Inheritance 教學](https://vinesmsuic.github.io/2020/01/06/c++-inheritance/) > C++ 其實有多重繼承,但他其實是有點糟糕的設計方式,我們不要學他。 > 等你們以後去學 JAVA 或其他語言會學到 super,學 super 比較重要。 > [ C++ 沒有 super ] > [name=Orange] ## 語法說明 相信你已經看完上面的參考資料摟! 而且有理解**衍生類別**與**基礎類別**的關係,這兩個名詞我們也常用一種代稱去形容他,衍生類別 = 子類別,基礎類別 = 父類別。子類別會繼承父類別的基本屬性與方法,而子類別亦可獨立出有別於父類別自己擁有的屬性與方法。 基本概念都有之後,來把語法記熟吧! > 以下例子為了演示方便,屬性、方法全都放 public,但理論上屬性應該要放 private,用 getter & setter 去存取他喔,封裝的概念不要忘記。 > [name=Orange] ```cpp= class Animal{ public: string type; void walk(){ cout << type << " walk" << endl;} void jump(){ cout << type << " jump" << endl;} }; class Dog : public Animal{ public: void bark(){ cout << type << " bark" << endl;} }; class Bird : public Animal{ public: void fly(){ cout << type << " fly" << endl;} }; int main() { Dog d1; d1.type = "dog"; d1.walk(); d1.jump(); d1.bark(); Bird b1; b1.type = "bird"; b1.walk(); b1.jump(); b1.fly(); return 0; } ``` 因為 Dog 跟 Bird 都公開繼承 Animal,所以子類別可以存取父類別的所有 public 屬性。 而繼承要使用的是 `:` 運算子,在要繼承別人的類別後加上 `:` `存取權限` `類別名稱`,這是固定語法。 公開繼承的概念就是 `is-a` 的概念,什麼意思呢? 看了上面繼承的例子,你會發現 Dog 跟 Bird 都可以使用父類別 (Animal) 的 public 屬性與方法,所以我們可以說 : ``` Bird is an Animal. Dog is an Animal. ``` 而這邊一直提到的公開繼承就是在 `:` 後加上的 public,寫 public、private、protected,其效果會有所不同。 這邊我們都先知道 public 公開繼承就可以了,當你公開繼承某個類別的時候,被繼承的類別的 public 屬性或方法都可以在子類別內被呼叫使用,而 private 屬性與方法則無法在子類別內直接呼叫使用。 > 上面說明的 public 與 private,有的是在表達繼承,有的是在表達類別內屬性與方法的權限,要會分哦。 > [name=Orange] ## [補充 - 自行閱讀]公開繼承? 私有繼承? 保護繼承? 上面說的內容與範例你了解了的話,你應該知道在 `:` 後寫不同的存取修飾子可能會有不同的事情產生,以下是參考資料,有問題歡迎來問我~ * [公開(public)繼承](https://openhome.cc/Gossip/CppGossip/PublicInheritance.html) * [保護(protected)繼承、私用(private)繼承](https://openhome.cc/Gossip/CppGossip/protectedPrivateInheritance.html) 這邊提的是繼承的模式哦! 不是類別內屬性與方法的存取權限。 <span style="color:red">**在往下閱讀之前,請務必先閱讀以下的參考資料。**</span> > 簡單的說,採用什麼類型的繼承,其繼承下來的屬性與方法就變成何種類型。 > [name=Orange] public 公開繼承就是上面的程式碼範例不再說明。 若為 protected 保護繼承,假設 Dog protected 繼承 Animal,程式碼像這樣。 ```cpp= class Animal{ public: string type; void walk(){ cout << type << " walk" << endl;} void jump(){ cout << type << " jump" << endl;} }; class Dog : protected Animal{ public: void bark(){ cout << type << " bark" << endl;} }; int main(){ Dog d1; d1.type = "dog"; d1.walk(); d1.jump(); } ``` <span style="color:red">**上面這樣的程式碼是錯的**</span>,因為保護繼承,Dog 繼承 Animal 之後對於 Dog 而言 type、jump、walk 全都變成 protected member,所以 Animal 的屬性與方法對於 Dog 而言,**只有 Dog 類別本身看的到**,實體化後的物件是無法存取的。 > protected member 的參考資料在最下面 > [name=Orange] 所以你必須在 Dog 類別內實作 getter & setter 才能存取 Animal 的 public 屬性與方法。像這樣。 ```cpp= class Animal{ public: string type; void walk(){ cout << type << " walk" << endl;} void jump(){ cout << type << " jump" << endl;} }; class Dog : protected Animal{ public: void bark(){ cout << type << " bark" << endl;} void set_type(string t){ type = t; } void walkAndJump(){ walk(); jump(); } }; int main(){ Dog d1; d1.set_type("dog"); d1.walkAndJump(); d1.bark(); } ``` 再延伸一點,假設今天有一隻可以從嘴巴噴火的狗狗,而且還會飛,那該怎麼辦,當然可以在現有的 Dog 內做改動,但如果又有一隻會招喚閃電,而且可以砍樹的狗狗,難道又要在 Dog 內增加嗎? 這樣其實沒甚麼效率,所以會再新增類別來繼承 Dog。但是因為繼承,所以 FireDog 仍舊保有 Dog 的屬性與方法。 ``` FireDog is a Dog! ``` ```cpp= class Animal{ public: string type; void walk(){ cout << type << " walk" << endl;} void jump(){ cout << type << " jump" << endl;} }; class Dog : protected Animal{ public: void bark(){ cout << type << " bark" << endl;} void set_type(string t){ type = t; } void walkAndJump(){ walk(); jump(); } }; class FireDog : public Dog{ public: void fire(){cout << type << " fire" << endl;} void fly(){cout << type << " fly" << endl;} }; ``` 請問對於 FireDog 而言,如果做 protected 繼承,該怎麼改寫程式呢? 更多變形留給大家自行思考,有問題歡迎來問~ ## [補充 - 自行閱讀] protected member 這邊提的是針對屬性與方法的存取權限,與上面完全不同,拜託請別搞混,分清楚。 * [受保護的(protected)成員](https://openhome.cc/Gossip/CppGossip/protectedMember.html)