PCDVD數位科技討論區

PCDVD數位科技討論區 (https://www.pcdvd.com.tw/index.php)
-   疑難雜症區 (https://www.pcdvd.com.tw/forumdisplay.php?f=34)
-   -   C#問題-多型 , 煩請高手大大解惑了~~ (https://www.pcdvd.com.tw/showthread.php?t=1072290)

SGI 2015-03-05 10:50 AM

C#問題-多型 , 煩請高手大大解惑了~~
 
高手大大們好~

小弟最近在研究C# 的多型, 有些寫法在網路跟書上常看到,但是就是不曉得這
樣寫是什麼意思, 又不想自己隨便亂猜測,所以請高手大大指點, 以下是範例:

有一基底類別 CarClass
class CarClass
{
public virtual void Run()
{
Console.WriteLine("Car is running");
}

public virtual string GetName()
{
return "Car";
}
}

以及一個衍生類別BenzClass

class BenzClass:CarClass
{
public override void Run()
{
Console.WriteLine("Benz is running!");
}

public new string GetName();
{
return "Benz";
}
}

客戶端的程式碼是:

static void Main(string[] args)
{
BenzClass Benz = new BenzClass();
CarClass Base = (CarClass)Benz;
Console.WriteLine(Benz.GetName());
Console.WriteLine(Base.GetName());
Console.ReadKey();
}

問題在客戶端程式碼這一行~
CarClass Base = (CarClass)Benz;

這是指物件Base 是將Benz 物件轉換成CarClass型別得到的嗎?
所以Base現在是屬於CarClass的實作物件囉?
如果是這樣, 為什麼不寫成 CarClass Base=new CarClass() 就好?
或者根本不是這樣?

上網路找多型資料, 結果好像大家對多型解釋不一, 有的跟繼承一點關係都沒有
. 就單純函式引數個數型別不同也有人稱為多型~~

煩請高手大大解惑了~

T磨人v2 2015-03-05 12:08 PM

就我對你問題的理解, 下面你參考 看看, 無針對語言性質.

多型其中一個用途, 當我寫好一個 methodA(BENZ) , 我可能目前只有 BENZ, 但以後有 LAMB 時, 這methodA 就不能用, 但如果是 methodA(CARClass),
CARClass defined method startUrEngine() , 並實做了大眾規格的啟動方式 , methodA 內部實做會呼叫 CARClass.startUrEngine,

BENZ 和 LAMB 繼承 CARClass ,
假如這兩台車啟動行為不同, BENZ 和 LAMB 就會 override startUrEngine , 實做自己所需要的內容, 如果 LAMB 是用 大眾規格啟動方式, 就無需實作自己的啟動行為 ,
但BENZ 啟動方式特殊, 所以他就override startUrEngine 實做自己的行為.
如此 methodA 不用因為今天多了 TOYOTA 這輛車就要改寫,只要他也繼承 CARClass 並override startUrEngine 實作了自己的行為.

這是多型的其中一種用法也有用 interface 來達到相同目的,
方法很多很難一一解釋, 端看你的需求而變化, 這邊只能說明概念, 希望有所幫助.

SGI 2015-03-05 12:42 PM

引用:
作者T磨人v2
就我對你問題的理解, 下面你參考 看看, 無針對語言性質.

多型其中一個用途, 當我寫好一個 methodA(BENZ) , 我可能目前只有 BENZ, 但以後有 LAMB 時, 這methodA 就不能用, 但如果是 methodA(CARClass),
CARClass defined method startUrEngine() , 並實做了大眾規格的啟動方式 , methodA 內部實做會呼叫 CARClass.startUrEngine,

BENZ 和 LAMB 繼承 CARClass ,
假如這兩台車啟動行為不同, BENZ 和 LAMB 就會 override startUrEngine , 實做自己所需要的內容, 如果 LAMB 是用 大眾規格啟動方式, 就無需實作自己的啟動行為 ,
但BENZ 啟動方式特殊, 所以他就override startUrEngine 實做自己的行為.
如此 methodA 不用因為今天多了 TOYOTA 這輛車就要改寫,只要他也繼承 CARClass 並override startUrEngine 實作了自己的行為.

這是多型的其中一種用法也有用 interface 來達到相同目的,
方法很...

感謝大大的指教~
不過大大你好像只是在解釋virtual 與 override 的概念
當基底類別方法有可能被衍生類別覆蓋, 就要使用override 或 new
我想這是許多物件導向語言共同的特性

我這邊的問題是 CarClass 與 BenzClass 是不同類別, 擁有自己的method
雖然BenzClass是CarClass的衍生類別
CarClass Base = (CarClass)Benz;
Base 是CarClass 的實作物件嗎? 或是只是由Benz物件轉型而來?
這樣寫法是有什麼含義嗎?

T磨人v2 2015-03-05 01:24 PM

BENZ 是繼承自 CarClass 理所當然可以轉型 CarClass
, 就你的code 他這樣轉不過是要呼叫 CarClass 所實作的 getName(), 這樣有什麼問題嗎?
還是我理解錯誤 ==???

harrisonlin 2015-03-05 01:39 PM

你的程式輸出是什麼?是否2行都是"Benz"?我不確定C#的method定義裡的"virtual","new"和"override"的意義,所以不確定.

就你的問題回答:

"CarClass Base = (CarClass)Benz;
Base 是CarClass 的實作物件嗎? 或是只是由Benz物件轉型而來?
這樣寫法是有什麼含義嗎?"

BenzClass繼承自CarClass,所以BenzClass的instance就是CarClass的instance.轉型只是我們想把Base這個物件當成CarClass的instance來操作.

這個例子裡只有一個super class和一個sub class,如果你多增加幾個sub class(BmwClass, AudiClass等等),然後生一個CarClass的容器(List, Set,或Array),任意丟一些上述sub class的instance進去,然後一個一個呼叫它們的run()或是getName()...

你有沒有發現到,你不需要知道這些容器裡的instance實際上是什麼型別(是Benz或BMW或Audi...),但它們都會"run",你呼叫它們的"getName()"都會回傳自己的名字.這就是一種"多型"的手法,你使用super class的界面(CarClass)操作sub class的實例,而不需要去cast它們,就可以得到sub class自己定義的行為.你可以運用這種手法,在程式中只使用super class,這樣往後你塞什麼sub class的instance,你的程式都不需要再大改了,這就是OOP的達到"元件重用"的方法之一.

T磨人v2 2015-03-05 01:48 PM

喔喔~~ 高手出現 說明果然 很清晰明瞭...... 給個 ∼讚∼

SGI 2015-03-05 01:49 PM

引用:
作者T磨人v2
BENZ 是繼承自 CarClass 理所當然可以轉型 CarClass
, 就你的code 他這樣轉不過是要呼叫 CarClass 所實作的 getName(), 這樣有什麼問題嗎?
還是我理解錯誤 ==???


喔喔~! 原來這就是轉型, 小弟買的書跟手上資料都沒有講到這一塊,
所以看到這種寫法, 熊熊給他不知道什麼意思~感謝大大, 現在有方向
可以去找資料了!!

SGI 2015-03-05 01:54 PM

引用:
作者harrisonlin
你的程式輸出是什麼?是否2行都是"Benz"?我不確定C#的method定義裡的"virtual","new"和"override"的意義,所以不確定.

就你的問題回答:

"CarClass Base = (CarClass)Benz;
Base 是CarClass 的實作物件嗎? 或是只是由Benz物件轉型而來?
這樣寫法是有什麼含義嗎?"

BenzClass繼承自CarClass,所以BenzClass的instance就是CarClass的instance.轉型只是我們想把Base這個物件當成CarClass的instance來操作.

這個例子裡只有一個super class和一個sub class,如果你多增加幾個sub class(BmwClass, AudiClass等等),然後生一個CarClass的容器(List, Set,或Array),任意丟一些上述sub class的instance進去,然後一個一個呼叫它們的run()或是getName()...

你有沒有發現到,你不需要知道這些容器裡的instance實際上是什麼型別(是Benz或BMW或Audi...),但它們...

是的, 兩行輸出都是Benz
大大你應該是相當資深的programmer
這種解釋內容我第一次看到, 跟網路上一堆八股說法截然不同
小弟一定會仔細研究~感謝兩位大大的幫忙, 讓小弟可以有方向可以繼續下去~!!

vxr 2015-03-05 02:35 PM

virtual修飾詞在父類別(第一次)的的設計上..
會要求對宣告virtual修飾詞的方法進行實作...
這個修飾詞有時會很有用, 對於某些C#設計者來說, 它幾乎非常實用....


override一般要求對父類別的抽象化實作(某些中文教科書(或譯本)對其行為稱作具象化..)...
因此搭配abstract進行覆寫...
在很多教科書說明, 對其抽象化類別實作該抽象方法, 這表示對於具象化類別來說..
這是一個方法簽名(簽章), 這是原文signature直接翻過去...

virtual我是沒有特別常用拉, 大多都是override去覆寫父類別(實作抽象)..

父類別與子類別是IS關係...
按照某些教科書的說法...
1. 符合LSP原則
2. 抽象化(abstract/interface)
3. 盡可能職責單一或最少, 這很重要.. 否則日後有時維護會賭爛...因為繼承就意味著偶合關係的增強..
4. 繼承超過三層以上的情況, 可能需要考慮重新設計或著在重新包裝(組合關係; HAVE/HAS)另外在 "注入". 除非你有把握日後腦袋還很靈光.
5. 當採用組合關係上去切割職責, 必須考慮其他原則, 例如LoD, 甚麼DIP等沙洨的.:unbelief:...

T磨人v2 2015-03-05 04:27 PM

補充一下我上一篇, 剛剛老闆飄過, 沒時間打玩,
你如果要呼叫父類別的方法 只能再子類別 override 的方法中 用 base.方法去呼叫.


所有的時間均為GMT +8。 現在的時間是05:19 AM.

vBulletin Version 3.0.1
powered_by_vbulletin 2025。