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)用是在運行時確定而不是編譯時。在.NET中用于實現(xiàn)多態(tài)性的關(guān)鍵詞有virtual、override、abstract、interface。
一、virtual實現(xiàn)多態(tài)
shape類是通用的基類,draw是一個虛方法,每個派生類都可以有自己的override版本,在運行時可以用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();
/*運行結(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修飾符后的程序運行結(jié)果,
/*運行結(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();
/*運行結(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();
}
}
/*運行結(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-05
C# 關(guān)于AppDomain的一些總結(jié)
這篇文章主要介紹了C# 關(guān)于AppDomain的一些總結(jié),幫助大家更好的理解和使用c#,感興趣的朋友可以了解下2021-02-02
C#中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

