[問題] 多型的問題

看板C_and_CPP (C/C++)作者 (改)時間14年前 (2012/03/09 23:40), 編輯推噓3(3034)
留言37則, 7人參與, 最新討論串1/3 (看更多)
假設我有一個食物的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

03/10 00:03, , 1F
隨便猜猜...在create裡面在多個參數如何?
03/10 00:03, 1F

03/10 00:03, , 2F
void Create(int foodType,...) {}
03/10 00:03, 2F

03/10 00:24, , 3F
樓上你說的方法是可行, 不過回過頭來想一想, 多型其實要
03/10 00:24, 3F

03/10 00:27, , 4F
捨棄省去的就是型別的概念, 也就是說這樣在Create裡還要
03/10 00:27, 4F

03/10 00:28, , 5F
傳入foodType的方式, 其實反而走了回頭路了...
03/10 00:28, 5F

03/10 00:32, , 6F
另外一點想問原po, 既然飲料你歸類成食物的一種, 為什麼
03/10 00:32, 6F

03/10 00:33, , 7F
你會出現IDrink這個想法出來?
03/10 00:33, 7F

03/10 00:40, , 8F
如果沒了IDrink, 你還需要CreateDrink嗎? 也許是你把事
03/10 00:40, 8F

03/10 00:41, , 9F
情給複雜化了! 再想一下, 你會得到答案的!
03/10 00:41, 9F

03/10 00:44, , 10F
C++有interface 這keyword?
03/10 00:44, 10F

03/10 00:45, , 11F
你的 Create 應該移到 ctor 才對吧
03/10 00:45, 11F

03/10 00:46, , 12F
除非你food跟drink之間有任何關聯,會用到同一個
03/10 00:46, 12F

03/10 00:46, , 13F
因為不同的食物 Create 方法不一樣,參數也不同
03/10 00:46, 13F

03/10 00:47, , 14F
而且照你的用法來看,產生食物後應該馬上呼叫 Create
03/10 00:47, 14F

03/10 00:47, , 15F
interface,否則你不應該將兩個東西從同一個源頭分出
03/10 00:47, 15F

03/10 00:48, , 16F
答案呼之欲出~~~
03/10 00:48, 16F

03/10 00:49, , 17F
不知道t大,我的想法是否正確?
03/10 00:49, 17F

03/10 00:50, , 18F
既然原po將drink當作是food,何不combine另一個class
03/10 00:50, 18F

03/10 00:59, , 19F
http://ideone.com/ViAsL 我講的大概是這個感覺
03/10 00:59, 19F

03/10 01:01, , 20F
http://ideone.com/mazyM 我會想寫成這樣XD
03/10 01:01, 20F

03/10 01:02, , 21F
這樣如果有其他食物也需要初始化參數,就可以方便使用
03/10 01:02, 21F

03/10 01:09, , 22F
j大return少了一個0 xdd
03/10 01:09, 22F

03/10 01:10, , 23F
map真得很好用,用一次就上癮了
03/10 01:10, 23F

03/10 01:11, , 24F
真的耶,其實main的那個return是貼上網頁之後才加的
03/10 01:11, 24F

03/10 04:00, , 25F
總結一下, 這個 IFood 是多餘的, IDrink 也是, 不覺得
03/10 04:00, 25F

03/10 04:01, , 26F
規範操作的 interface 還要有 GetName()、GetPrice()
03/10 04:01, 26F

03/10 04:02, , 27F
很詭異嗎? 大家都把 Abstract Class 跟 Interface 搞
03/10 04:02, 27F

03/10 04:02, , 28F
混了, 如果是我會創兩個 class: HasPrice、HasName
03/10 04:02, 28F

03/10 04:03, , 29F
會有預設的 Get/Set 方法跟行為, 你的所有食物就繼承
03/10 04:03, 29F

03/10 04:04, , 30F
這兩個類別即可, 如果你在同一段程式碼內都需要存取
03/10 04:04, 30F

03/10 04:05, , 31F
名稱跟價格資訊, 再考慮多一個 HasNameAndPrice, 那些
03/10 04:05, 31F

03/10 04:06, , 32F
需要不同參數的創造物件方法, 實際上就是建構子本身,
03/10 04:06, 32F

03/10 04:07, , 33F
除了一些比較特定的服務架構需要將 C++物件跟 service
03/10 04:07, 33F

03/10 04:07, , 34F
物件生命週期分開談, 否則物件一被創造出來就是馬上可
03/10 04:07, 34F

03/10 04:08, , 35F
以使用的, 沒有什麼"必須呼叫什麼方法才能使用"這回事
03/10 04:08, 35F

03/10 10:42, , 36F
感謝板主,受教了!
03/10 10:42, 36F

03/11 23:52, , 37F
看來在Create中加一個參數是不錯的選擇
03/11 23:52, 37F
文章代碼(AID): #1FMYHpOq (C_and_CPP)
文章代碼(AID): #1FMYHpOq (C_and_CPP)