[問題] 關於多型的問題

看板C_and_CPP (C/C++)作者 (...)時間12年前 (2014/02/05 11:20), 編輯推噓2(2096)
留言98則, 4人參與, 最新討論串1/1
我是用Blocks 10.05 程式是這樣 class A { public: virtual char printB1(){ return 'A'; } char printB2(){ return 'B'; } char doPrintB1(){ return printB1(); } char doPrintB2(){ return printB2(); } }; class B : public A { public: char printB1(){ return 'C'; } char printB2(){ return 'D'; } // char doPrintB1(){ // return printB1(); // } // char doPrintB2(){ // return printB2(); // } }; int main(int argc, char *argv[]) { A a=A(); B b=B(); A ab=B(); cout<<a.doPrintB1(); cout<<a.doPrintB2(); cout<<b.doPrintB1(); cout<<b.doPrintB2(); cout<<ab.doPrintB1(); cout<<ab.doPrintB2(); cout<<ab.printB1(); cout<<ab.printB2(); cout<<"*****************"; A *ap=new A(); B *bp=new B(); A *abp=new B(); cout<<ap->doPrintB1(); cout<<ap->doPrintB2(); cout<<bp->doPrintB1(); cout<<bp->doPrintB2(); cout<<abp->doPrintB1(); cout<<abp->doPrintB2(); cout<<abp->printB1(); cout<<abp->printB2(); return 0; } 印出 ABCBABAB*****************ABCBCBCB 不懂為何會不一樣??用A ab=B(); 為何沒有多形的效果出來,但是A *abp=new B() 卻有 另外當我把 B的註解拿掉後,出現 ABCDABAB*****************ABCDCBCB 不懂為何會和上面不一樣?? 我雖然是override,但是內容都相同呀~~~ P.S. B Class裡的那段 public: 再沒拿註解時是可以不用加的,但是拿掉後沒加卻出現 'char B::doPrintB1()' is private| 這個錯誤 我覺得不合理呀 因為我一開始就宣告Class B:public A 照理說應該不會有這個錯誤,因為A 裡的method我都宣告為public了 請各位高手幫我解惑一下 (因為之前是學java,我用java跑這兩個例子,出現結果都是一樣而且均有多形出現) -- 苦海無涯。施主,執著何必呢? 無涯苦海。大師,何必渡吾呢? -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 60.249.193.174 ※ 編輯: scale0125 來自: 60.249.193.174 (02/05 11:24)

02/05 11:33, , 1F
多型在 C++ 中有些東西要處理. 1. 只能用指標或參考
02/05 11:33, 1F

02/05 11:34, , 2F
2. 需要對被 override 的函式加 virtual
02/05 11:34, 2F

02/05 11:35, , 3F
此外 "is private" 的問題在於類別成員預設為 private
02/05 11:35, 3F

02/05 11:36, , 4F
註解拿掉的問題在於 printB2 在 A 跟 B 中是不同的.
02/05 11:36, 4F

02/05 11:46, , 5F
我現在才知道A ab=B()原來可編譯而且Wall也沒警告...
02/05 11:46, 5F

02/05 11:49, , 6F
因為那是合法的 "轉型"
02/05 11:49, 6F

02/05 12:09, , 7F
感謝F大的解答,我比較疑或的是我用了繼承,為何
02/05 12:09, 7F

02/05 12:11, , 8F
printB2 在 A,B 中是不同的。
02/05 12:11, 8F

02/05 12:13, , 9F
因為 A 跟 B 本來就是不同的. XD.
02/05 12:13, 9F

02/05 12:14, , 10F
要一樣的話, 你在 B 裡面就不要宣告 printB2
02/05 12:14, 10F

02/05 12:14, , 11F
或者在 doPrintB2 裡面呼叫 A::printB2
02/05 12:14, 11F

02/05 12:15, , 12F
所以我可以說 printB2在B中有兩個嗎?
02/05 12:15, 12F

02/05 12:16, , 13F
因為沒有加virtual 所以有一個是public,另一個是privat
02/05 12:16, 13F

02/05 12:16, , 14F
可以這麼說吧. 分別是 A::printB2 跟 B::printB2
02/05 12:16, 14F

02/05 12:16, , 15F
這樣也不算是overloading,我的參數都是空的
02/05 12:16, 15F

02/05 12:19, , 16F
也不全然不算 overloading, 你可以把 this 想成參數之一
02/05 12:19, 16F

02/05 12:19, , 17F
只是跟 override 關係比較大, 很多名稱遮蔽的結果
02/05 12:19, 17F

02/05 12:26, , 18F
從我的角度來看, 只要有宣告定義一個函式有沒有加 virtual
02/05 12:26, 18F

02/05 12:26, , 19F
並沒有影響. 都是會 "多一個" 函式
02/05 12:26, 19F

02/05 12:27, , 20F
virtual 影響的是呼叫機制.
02/05 12:27, 20F

02/05 12:28, , 21F
override 並不是重新定義函式. 這點要先了解
02/05 12:28, 21F

02/05 12:29, , 22F
只是印象中 Java 裡有重新定義這樣好的錯覺 (十年沒寫過了.)
02/05 12:29, 22F

02/05 13:29, , 23F
這樣說來,一開始在B裡沒有寫public: 的話
02/05 13:29, 23F

02/05 13:31, , 24F
printB1,printB2都算B裡新的private的函數
02/05 13:31, 24F

02/05 13:32, , 25F
而非所謂的override了,是這樣嗎?但是加了virtual卻有效
02/05 13:32, 25F

02/05 14:09, , 26F
Override 不是重新定義,就算Java 也是產生新的
02/05 14:09, 26F

02/05 14:10, , 27F
virtual 是讓那個函式用起來有多型效果
02/05 14:10, 27F

02/05 14:11, , 28F
只是 Java 預期你會 override ,所以不用加 virtual
02/05 14:11, 28F

02/05 14:13, , 29F
剛剛就第二個case把virtual拿掉
02/05 14:13, 29F

02/05 14:14, , 30F
出現ABCDABAB*****************ABCDABAB
02/05 14:14, 30F

02/05 14:14, , 31F
本來預期出現 ABABABAB*****************ABABABAB 說
02/05 14:14, 31F

02/05 14:15, , 32F
你的預期毫無道理,沒有 virtual (override)的情況下這結果
02/05 14:15, 32F

02/05 14:16, , 33F
很直觀
02/05 14:16, 33F

02/05 14:17, , 34F
A 兩個 print 都加 virtual 就是你要的
02/05 14:17, 34F

02/05 14:17, , 35F
可是我Class B裡的 method都是放在public:底下
02/05 14:17, 35F

02/05 14:18, , 36F
3跟 public 無關
02/05 14:18, 36F

02/05 14:18, , 37F
在沒有virtual的狀況下 應該是要執行父類別的
02/05 14:18, 37F

02/05 14:19, , 38F
X多型的做法請參考第一推
02/05 14:19, 38F

02/05 14:20, , 39F
XX為什麼是父類別
02/05 14:20, 39F

02/05 14:20, , 40F
Sorry 手機軟體怪怪的,忽略前面的 X
02/05 14:20, 40F

02/05 14:21, , 41F
因為我看書上是說 子類別的public:底下是放新的method或
02/05 14:21, 41F

02/05 14:21, , 42F
放 要override的 method
02/05 14:21, 42F

02/05 14:22, , 43F
是啊,但沒有 virtual 就沒 override. 請看前兩推
02/05 14:22, 43F

02/05 14:23, , 44F
您第一推的多形我大概了解,反而是子類別宣告放子物件
02/05 14:23, 44F

02/05 14:23, , 45F
我目前還沒想通
02/05 14:23, 45F

02/05 14:25, , 46F
那你還去重看書,忘了 Java,
02/05 14:25, 46F

02/05 14:29, , 47F
也是,感謝大大回答,我再整理一下,感謝感謝。
02/05 14:29, 47F

02/05 16:04, , 48F
我發現我不懂的是 子物件b呼叫doPrintB1,doPrintB2時
02/05 16:04, 48F

02/05 16:05, , 49F
不是直接調用自己的而是還要使用父類別的doPrintB1,
02/05 16:05, 49F

02/05 16:05, , 50F
及doPrintB2
02/05 16:05, 50F

02/05 16:12, , 51F
是用自己的沒錯啊
02/05 16:12, 51F

02/05 16:13, , 52F
自己沒有的話才找父類別
02/05 16:13, 52F

02/05 16:15, , 53F
以case1的例子就是找父類別的,對吧~~
02/05 16:15, 53F

02/05 16:17, , 54F
然後 父類別的doPrintB1,doPrintB2裡面的method是父子
02/05 16:17, 54F

02/05 16:17, , 55F
Case1 是哪個?
02/05 16:17, 55F

02/05 16:17, , 56F
都有的
02/05 16:17, 56F

02/05 16:18, , 57F
都有什麼?
02/05 16:18, 57F

02/05 16:18, , 58F
就是remark沒有拿掉 ClassB裡面只有printB1,printB2
02/05 16:18, 58F

02/05 16:19, , 59F
對啊
02/05 16:19, 59F

02/05 16:21, , 60F
此時子物件透過doPrintB1,doPrintB2去找父類別裡的
02/05 16:21, 60F

02/05 16:21, , 61F
printB1,printB2
02/05 16:21, 61F

02/05 16:21, , 62F
我不懂的是 子物件也有printB1,printB2
02/05 16:21, 62F

02/05 16:22, , 63F
為何不是直接去找子類別的printB1,printB2
02/05 16:22, 63F

02/05 16:23, , 64F
因為b本身是子物件,宣告時也是用子類別宣告
02/05 16:23, 64F

02/05 16:24, , 65F
我以為就只是繼承doPrintB1,doPrintB2然後去找自己的
02/05 16:24, 65F

02/05 16:25, , 66F
printB1,printB2
02/05 16:25, 66F

02/05 16:25, , 67F
父類別函式呼叫父類別函式不是天經地義嗎
02/05 16:25, 67F

02/05 16:26, , 68F
但是繼承的話不是會把父類別的函式放到子類別中~~
02/05 16:26, 68F

02/05 16:30, , 69F
看你怎麼想
02/05 16:30, 69F

02/05 16:31, , 70F
是也不是,重點是他呼叫的是哪個
02/05 16:31, 70F

02/05 16:34, , 71F
因為我用java卻去寫 子物件,宣告時也是用子類別宣告
02/05 16:34, 71F

02/05 16:35, , 72F
然後也是不在子類別裡寫doPrintB1,doPrintB2
02/05 16:35, 72F

02/05 16:36, , 73F
這不是 Java
02/05 16:36, 73F

02/05 16:36, , 74F
結果卻是呼叫子類別的printB1,printB2
02/05 16:36, 74F

02/05 16:37, , 75F
要像 Java 請加 virtual ,說很多次了,難道Java有 virtual
02/05 16:37, 75F

02/05 16:37, , 76F
所以一直想不通。
02/05 16:37, 76F

02/05 16:38, , 77F
沒有 所以在java裡面其實只有實驗doPrintB2呼叫printB2
02/05 16:38, 77F

02/05 16:40, , 78F
但我都是用 子類別宣告,子物件去做呼叫
02/05 16:40, 78F

02/05 16:41, , 79F
那妳到底加 virtual 了沒? 這不是 java
02/05 16:41, 79F

02/05 16:43, , 80F
printB1有加,printB2沒有
02/05 16:43, 80F

02/05 16:44, , 81F
都加可以嗎~
02/05 16:44, 81F

02/05 16:48, , 82F
都加的話 b.doPrintB1印出C , b.doPrintB1印出D
02/05 16:48, 82F

02/05 16:49, , 83F
不是你要的嗎?
02/05 16:49, 83F

02/05 16:51, , 84F
恩該怎麼說呢,我以為在case1的情況下,
02/05 16:51, 84F

02/05 16:51, , 85F
不管有沒有加virtual, 子類別宣告,子物件去做呼叫
02/05 16:51, 85F

02/05 16:52, , 86F
doPrintB1,doPrintB2 都應該是 C 和 D
02/05 16:52, 86F

02/05 16:53, , 87F
為什麼一定要這樣呢
02/05 16:53, 87F

02/05 16:54, , 88F
當然這是我在實際跑程式之前"自己認為"
02/05 16:54, 88F

02/05 16:54, , 89F
明明就不是 b 的 doPrint, 你還是把 java 忘掉去看書
02/05 16:54, 89F

02/05 16:57, , 90F
上面 b 是 B
02/05 16:57, 90F

02/05 16:57, , 91F
java C# as 用久了,C++多形容易搞混...
02/05 16:57, 91F

02/05 16:58, , 92F
所以我才會有case2出來,才知道case1不是我想的那樣將
02/05 16:58, 92F

02/05 16:59, , 93F
doPrintB1,doPrintB2視為子類別的method
02/05 16:59, 93F

02/05 17:00, , 94F
再次感謝F大花了那麼多時間協助 <(__)>
02/05 17:00, 94F

02/05 17:01, , 95F
明明 Java 也不是
02/05 17:01, 95F

02/05 17:02, , 96F
好吧,這麼說也不對
02/05 17:02, 96F

02/05 17:03, , 97F
恩 我算是用結果論去猜
02/05 17:03, 97F

02/05 17:07, , 98F
所以遇到不同題型就掛了...
02/05 17:07, 98F
文章代碼(AID): #1IyQtr_B (C_and_CPP)
文章代碼(AID): #1IyQtr_B (C_and_CPP)