看板 C_and_CPP 關於我們 聯絡資訊
假設我有一個食物的interface,如下: interface IFood { virtual void Create() = 0; virtual char* GetName() = 0; virtual int GetPrice() = 0; }; 食物可以被創造,然後取得食物的名字和價格 繼承此interface的class如下: class CBeef : public IFood { ... }; class CLamb : public IFood { ... }; class CChicken : public IFood { ... }; 於是我可以使用多型的好處: IFood *pFood = NULL; switch(yourOrder) { case ORDER_BEEF: pFood = new Beef(); break; case ORDER_LAMB: pFood = new CLamb(); break; case ORDER_CHICKEN: pFood = new CChicken() break; }; pFood->Create(); cout << "Name: " << pFood->GetName() << endl; cout << "Price: " << pFood->GetPrice() << endl; ... pFood->GetName()和pFood->GetPrice()會根據傳入的yourOrder變數而有所改變 但是當我加入了另一種食物,比方說 interface IDrink : IFood { virtual void CreateDrink(int nIce) = 0; }; 飲料也是食物的一種,也需要取得價格和名字,所以繼承自IFood 但不同的是創造飲料需要冰塊,所以我沒辦法用原本IFood::Create()來創造飲料 繼承飲料的class如下: class CCoke : public IDrink() { public: void CreateDrink(int nIce) {...} void Create() { //do nothing } char* GetName() { ... } int GetPrice() { ... } }; class CTea : public IDrink() { public: void CreateDrink(int nIce) {...} void Create() { //do nothing } char* GetName() { ... } int GetPrice() { ... } }; 因為還是要實作IFood的純虛擬函數,所以只好在Create()內甚麼事也不作 這樣感覺就有點累贅,繼承了一個我不需要的method 而且在使用上也沒有之前那麼俐落了,我還必須判斷目前pFood指向的是飲料還食物 若是一般的食物我就使用pFood->Create(); 若是飲料我就必須把pFood轉型成IDrink,然後使用CreateDrink(); 該怎麼改code,讓程式比較簡潔呢?? -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 111.240.139.207
cuteclare:隨便猜猜...在create裡面在多個參數如何? 03/10 00:03
cuteclare:void Create(int foodType,...) {} 03/10 00:03
tomnelson:樓上你說的方法是可行, 不過回過頭來想一想, 多型其實要 03/10 00:24
tomnelson:捨棄省去的就是型別的概念, 也就是說這樣在Create裡還要 03/10 00:27
tomnelson:傳入foodType的方式, 其實反而走了回頭路了... 03/10 00:28
tomnelson:另外一點想問原po, 既然飲料你歸類成食物的一種, 為什麼 03/10 00:32
tomnelson:你會出現IDrink這個想法出來? 03/10 00:33
tomnelson:如果沒了IDrink, 你還需要CreateDrink嗎? 也許是你把事 03/10 00:40
tomnelson:情給複雜化了! 再想一下, 你會得到答案的! 03/10 00:41
diabloevagto:C++有interface 這keyword? 03/10 00:44
littleshan:你的 Create 應該移到 ctor 才對吧 03/10 00:45
diabloevagto:除非你food跟drink之間有任何關聯,會用到同一個 03/10 00:46
littleshan:因為不同的食物 Create 方法不一樣,參數也不同 03/10 00:46
littleshan:而且照你的用法來看,產生食物後應該馬上呼叫 Create 03/10 00:47
diabloevagto:interface,否則你不應該將兩個東西從同一個源頭分出 03/10 00:47
tomnelson:答案呼之欲出~~~ 03/10 00:48
diabloevagto:不知道t大,我的想法是否正確? 03/10 00:49
diabloevagto:既然原po將drink當作是food,何不combine另一個class 03/10 00:50
diabloevagto:http://ideone.com/ViAsL 我講的大概是這個感覺 03/10 00:59
james732:http://ideone.com/mazyM 我會想寫成這樣XD 03/10 01:01
james732:這樣如果有其他食物也需要初始化參數,就可以方便使用 03/10 01:02
diabloevagto:j大return少了一個0 xdd 03/10 01:09
diabloevagto:map真得很好用,用一次就上癮了 03/10 01:10
james732:真的耶,其實main的那個return是貼上網頁之後才加的 03/10 01:11
loveme00835:總結一下, 這個 IFood 是多餘的, IDrink 也是, 不覺得 03/10 04:00
loveme00835:規範操作的 interface 還要有 GetName()、GetPrice() 03/10 04:01
loveme00835:很詭異嗎? 大家都把 Abstract Class 跟 Interface 搞 03/10 04:02
loveme00835:混了, 如果是我會創兩個 class: HasPrice、HasName 03/10 04:02
loveme00835:會有預設的 Get/Set 方法跟行為, 你的所有食物就繼承 03/10 04:03
loveme00835:這兩個類別即可, 如果你在同一段程式碼內都需要存取 03/10 04:04
loveme00835:名稱跟價格資訊, 再考慮多一個 HasNameAndPrice, 那些 03/10 04:05
loveme00835:需要不同參數的創造物件方法, 實際上就是建構子本身, 03/10 04:06
loveme00835:除了一些比較特定的服務架構需要將 C++物件跟 service 03/10 04:07
loveme00835:物件生命週期分開談, 否則物件一被創造出來就是馬上可 03/10 04:07
loveme00835:以使用的, 沒有什麼"必須呼叫什麼方法才能使用"這回事 03/10 04:08
diabloevagto:感謝板主,受教了! 03/10 10:42
pracinverse:看來在Create中加一個參數是不錯的選擇 03/11 23:52