C#中多態(tài)現(xiàn)象和多態(tài)的實現(xiàn)方法
本文實例講述了C#中多態(tài)現(xiàn)象和多態(tài)的實現(xiàn)方法。分享給大家供大家參考。具體分析如下:
面向?qū)ο蟮奶卣鞣庋b、繼承和多態(tài)。Polymorphism(多態(tài)性)來源于希臘單詞,指“多種形態(tài)”。多態(tài)性的一個重要特征是方法的調(diào)用是在運(yùn)行時確定而不是編譯時。在.NET中用于實現(xiàn)多態(tài)性的關(guān)鍵詞有virtual、override、abstract、interface。
一、virtual實現(xiàn)多態(tài)
shape類是通用的基類,draw是一個虛方法,每個派生類都可以有自己的override版本,在運(yùn)行時可以用shape類的變量動態(tài)的調(diào)用draw方法。
public class Shape { public virtual void Draw() { Console.WriteLine("base class drawing"); } } public class Rectangle :Shape { public override void Draw() { Console.WriteLine("Drawing a Rectangle"); } } public class Square :Rectangle { public override void Draw() { Console.WriteLine("Drawing a Square"); base.Draw(); } } class Program { static void Main(string[]args) { System.Collections.Generic.List<Shape> shapes =new List<Shape>(); shapes.Add(new Rectangle()); shapes.Add(new Square()); foreach(Shape s in shapes) { s.Draw(); } Console.ReadKey(); /*運(yùn)行結(jié)果 Drawing a Rectangle Drawing a Square Drawing a Rectangle */ } }
方法、屬性、事件、索引器都可以被virtual修飾,但是字段不可以。派生類必須用override表示類成員參與虛調(diào)用。假如把Square中的draw方法替換為用new 修飾,則表示draw方法不參與虛調(diào)用,而且是一個新的方法,只是名字和基類方法重名。
public new void Draw() { Console.WriteLine("Drawing a Square"); base.Draw(); }
這個方法在Main方法中的foreach中將不會被調(diào)用,它不是虛方法了。用new修飾符后的程序運(yùn)行結(jié)果,
/*運(yùn)行結(jié)果 Drawing a Rectangle Drawing a Rectangle */
假如說虛方法在rectangle擴(kuò)展后,不希望square擴(kuò)展了,可以在方法前加上sealed修飾符,
如下
public class Rectangle :Shape { public sealed override voidDraw() { Console.WriteLine("Drawing a Rectangle"); } }
當(dāng)派生類重寫某個虛擬成員時,即使該派生類的實例被當(dāng)作基類的實例訪問或者把派生類實例賦給父類變量進(jìn)行訪問,但是還是會調(diào)用派生類重寫后的成員,可以把代碼改為如下形式,
static void Main(string[] args) { System.Collections.Generic.List<Shape>shapes =new List<Shape>(); shapes.Add((Shape)new Rectangle()); shapes.Add((Shape)new Square()); foreach(Shape s inshapes) { s.Draw(); } Console.ReadKey(); /*運(yùn)行結(jié)果 Drawing a Rectangle Drawing a Square Drawing a Rectangle */ }
二、abstract實現(xiàn)多態(tài)
被abstract修飾的方法,默認(rèn)是虛擬的,但是不能出現(xiàn)virtual關(guān)鍵詞修飾。被abstract修飾的類可以有已實現(xiàn)的成員,可以有自己的字段,可以有非abstract 修飾的方法,但是不能實例化因為抽象的東西是沒有實例對應(yīng)的。比如,有人讓我們畫個圖形(抽象)是畫不出來的,但是讓畫個矩形(具體)是可以畫出來的。下面是用abstract實現(xiàn)的多態(tài)版本,
public abstract classShape { public abstract void Draw(); } public class Rectangle :Shape { public override void Draw() { Console.WriteLine("Drawing a Rectangle"); } } public class Square :Rectangle { public override void Draw() { Console.WriteLine("Drawing a Square"); base.Draw(); } } class Program { static void Main(string[]args) { System.Collections.Generic.List<Shape>shapes =new List<Shape>(); shapes.Add(new Rectangle()); shapes.Add(new Square()); foreach(Shape s in shapes) { s.Draw(); } Console.ReadKey(); } }
被abstract修飾的方法,在派生類中同樣用override關(guān)鍵詞進(jìn)行擴(kuò)展。同樣可以用關(guān)鍵詞sealed阻止派生類進(jìn)行擴(kuò)展。
interface實現(xiàn)多態(tài)
接口可由方法、屬性、事件、索引器或這四種成員類型的任何組合構(gòu)成。接口不能包含字段。接口成員默認(rèn)是公共的,抽象的,虛擬的。若要實現(xiàn)接口成員,類中的對應(yīng)成員必須是公共的、非靜態(tài)的,并且與接口成員具有相同的名稱和簽名。下面是interface實現(xiàn)的多態(tài)版本
public interface IShape { void Draw(); } public class Rectangle :IShape { public void Draw() { Console.WriteLine("Drawing a Rectangle"); } } public class Square: IShape { public void Draw() { Console.WriteLine("Drawing a Square"); } } class Program { static void Main(string[]args) { System.Collections.Generic.List<IShape>shapes =new List<IShape>(); shapes.Add(new Rectangle()); shapes.Add(new Square()); foreach(IShape s inshapes) { s.Draw(); } Console.ReadLine(); } }
抽象類與接口
類可以實現(xiàn)無限個接口,但僅能從一個抽象(或任何其他類型)類繼承。從抽象類派生的類仍可實現(xiàn)接口。msdn的在接口和抽象類的選擇方面給的一些建議,
如果預(yù)計要創(chuàng)建組件的多個版本,則創(chuàng)建抽象類。抽象類提供簡單易行的方法來控制組件版本。通過更新基類,所有繼承類都隨更改自動更新。另一方面,接口一旦創(chuàng)建就不能更改。如果需要接口的新版本,必須創(chuàng)建一個全新的接口。
如果創(chuàng)建的功能將在大范圍的全異對象間使用,則使用接口。抽象類應(yīng)主要用于關(guān)系密切的對象,而接口最適合為不相關(guān)的類提供通用功能。
如果要設(shè)計小而簡練的功能塊,則使用接口。如果要設(shè)計大的功能單元,則使用抽象類。
如果要在組件的所有實現(xiàn)間提供通用的已實現(xiàn)功能,則使用抽象類。抽象類允許部分實現(xiàn)類,而接口不包含任何成員的實現(xiàn)。
一個綜合性的實例
public interface IShape { void Draw(); } public class Shape:IShape { void IShape.Draw() { Console.WriteLine("Shape IShape.Draw()"); } public virtual void Draw() { Console.WriteLine("Shape virtual Draw()"); } } public class Rectangle :Shape,IShape { void IShape.Draw() { Console.WriteLine("Rectangle IShape.Draw()"); } public newvirtual void Draw() { Console.WriteLine("Rectangle virtual Draw()"); } } public class Square :Rectangle { public override void Draw() { Console.WriteLine("Square override Draw()"); } } class Program { static void Main(string[]args) { Square squre = new Square(); Rectangle rect = squre; Shape shape = squre; IShape ishape = squre; squre.Draw(); rect.Draw(); shape.Draw(); ishape.Draw(); Console.ReadLine(); } } /*運(yùn)行結(jié)果: Square override Draw()① Square override Draw()② Shape virtual Draw()③ Rectangle IShape.Draw()④ */
在這個程序里,把派生類實例賦給父類變量或者接口。對結(jié)果①無需解釋。結(jié)果②,因為Draw方法是虛方法,虛方法的調(diào)用規(guī)則是調(diào)用離實例變量最近的override版本方法,Square類中的Draw方法是離實例square最近的方法,即使是把Square類型的實例賦值給Rectangle類型的變量去訪問,仍然調(diào)用的是Square類重寫的方法。對于結(jié)果③,也是虛方法調(diào)用,在子類Rectangle中的draw方法用new修飾,這就表明shape類中的virtual到此中斷,后面Square中的override版是針對Rectangle中的Draw方法,此時,離square實例最近的實現(xiàn)就是Shape類中的Draw 方法,因為Shape類中的Draw方法沒有override的版本只能調(diào)用本身的virtual版了。結(jié)果④,因為Rectangle重新聲明實現(xiàn)接口IShape,接口調(diào)用同樣符合虛方法調(diào)用規(guī)則,調(diào)用離它最近的實現(xiàn),Rectangle中的實現(xiàn)比Shape中的實現(xiàn)離實例square更近。Rectangle中的IShape.Draw()方法是顯式接口方法實現(xiàn),對于它不能有任何的訪問修飾符,只能通過接口變量訪問它,同時也不能用virtual或者override進(jìn)行修飾,也不能被派生類型調(diào)用。只能用IShape變量進(jìn)行訪問。如果類型中有顯式接口的實現(xiàn),而且用的是接口變量,默認(rèn)調(diào)用顯式接口的實現(xiàn)方法。
override和方法選擇
public class Base { public virtual void Write(int num) { Console.WriteLine("int:" + num.ToString()); } } public class Derived :Base { public override void Write(int num) { Console.WriteLine("derived:" + num.ToString()); } public void Write(double num) { Console.WriteLine("derived double:" + num.ToString()); } }
希望本文所述對大家的C#程序設(shè)計有所幫助。
相關(guān)文章
C#使用ODBC與OLEDB連接數(shù)據(jù)庫的方法示例
這篇文章主要介紹了C#使用ODBC與OLEDB連接數(shù)據(jù)庫的方法,結(jié)合實例形式分析了C#基于ODBC與OLEDB實現(xiàn)數(shù)據(jù)庫連接操作簡單操作技巧,需要的朋友可以參考下2017-05-05C# 關(guān)于AppDomain的一些總結(jié)
這篇文章主要介紹了C# 關(guān)于AppDomain的一些總結(jié),幫助大家更好的理解和使用c#,感興趣的朋友可以了解下2021-02-02C#中WPF內(nèi)存回收與釋放LierdaCracker的實現(xiàn)
本文主要介紹了C#中WPF內(nèi)存回收與釋放LierdaCracker的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07