首先理解一下什麼叫多態。同一操作作用於不同的對象,可以有不同的解釋,產生不同的執行結果,這就是多態性。
多態性通過派生類覆蓋基類中的虛函數型方法來實現。
多態性分爲兩種,一種是編譯時的多態性,一種是運行時的多態性。
編譯時的多態性:編譯時的多態性是通過重載來實現的。對於非虛的成員來說,系統在編譯時,根據傳遞的參數、返回的類型等信息決定實現何種操作。
運行時的多態性:運行時的多態性就是指直到系統運行時,才根據實際情況決定實現何種操作。C#中運行時的多態性是通過覆蓋虛成員實現。
舉例:
using System;
public class DrawingBase
{
public virtual void Draw()
{
Console.WriteLine("I'm just a generic drawing object.");
}
}
public class Line : DrawingBase
{
public override void Draw()
{
Console.WriteLine("I'm a Line.");
}
}
public class Circle : DrawingBase
{
public override void Draw()
{
Console.WriteLine("I'm a Circle.");
}
}
public class Square : DrawingBase
{
public override void Draw()
{
Console.WriteLine("I'm a Square.");
}
}
public class DrawDemo
{
public static int Main(string[] args)
{
DrawingBase[] dObj = new DrawingBase[4];
dObj[0] = new Line();
dObj[1] = new Circle();
dObj[2] = new Square();
dObj[3] = new DrawingBase();
foreach (DrawingBase drawObj in dObj)
drawObj.Draw();
return 0;
}
}
下面我們來分別說明一下多態中涉及到的四個概念:重載,覆蓋,虛方法和抽象方法。
4.1 重載 在面對對象這樣的高級語言中都允許我們在一個類中定義多個方法名相同、方法間參數個數和參數順序不同的方法,對於參數個數不同或者參數列表不同的情況我們稱之爲參數列表不同。需要注意的是這裏沒有提到方法的返回值。
特點(兩必須一可以)
方法名必須相同
參數列表必須不相同
返回值類型可以不相同
public int Calculate(int x, int y)
public double Calculate(double x, double y)
舉例:
public class Test
{
public int Calculate(int x, int y)
{
return x + y;
}
public double Calculate(double x, double y)
{
return x + y;
}
}
4.2 覆蓋 子類中,爲滿足自己的需要來重複定義某個方法的不同實現。
定義:通過使用關鍵字override來覆蓋
public override bool abc(...)
注意:只有虛方法和抽象方法才能被覆蓋
要求:
*相同的方法名稱
*相同的參數列表
*相同的返回值類型
例:
public class Test
{
public virtual int Calculate(int x, int y)
{
return x + y;
}
public virtual double Calculate(double x, double y)
{
return x + y;
}
}
派生類(子類)
public class TestOverride : Test
{
public override int Calculate(int x, int y)
{
return x * y;
}
public override double Calculate(double x, double y)
{
return x * y;
}
}
首先看這個類,我們在同一個類中滿足了重載的三個特點,方法名必須相同Calculate;參數列表必須不相同第一個方法的兩個參數類型爲int類型,第二個方法的兩個參數類型爲double類型;返回值類型可以不相同一個返回值類型爲int,另一個返回值類型爲double。
4.3虛方法
當類中的方法聲明前加上了virtual修飾符,我們稱之爲虛方法,反之爲非虛。使用了virtual修飾符後,不允許再有static,abstract,或override修飾符。
對於非虛的方法,無論被其所在類的實例調用,還是被這個類的派生類的實例調用,方法的執行方式不變。而對於虛方法,它的執行方式可以被派生類改變,這種改變是通過方法的重載來實現的。
特點:
●聲明使用virtual關鍵字。
●調用虛方法,運行時將確定調用對象是什麼類的實例,並調用適當的覆寫的方法。
●虛方法可以有實現體。
下面的例子說明了虛方法與非虛方法的區別。
例子:
using System;
class A
{
public void F() { Console.WriteLine("A.F"); }
public virtual void G() { Console.WriteLine("A.G"); }
}
class B : A
{
new public void F() { Console.WriteLine("B.F"); }
public override void G() { Console.WriteLine("B.G"); }
}
class Tese
{
static void Main()
{
B b = new B();
A a = b;
a.F();
b.F();
a.G();
b.G();
}
}
例子中,A類提供了兩個方法:非虛的F和虛方法G.類B則提供了一個新的非虛的方法F,從而覆蓋了繼承的F;類B同時還重載了繼承的方
法G.那麼輸出應該是:
A.F
B.F
B.G
B.G
注意到本例中,方法a.G()實際調用了B.G,而不是A.G.這是因爲編譯時值爲A,但運行時值爲B,所以B完成了對方法的實際調用.
4.4抽象類與方法
抽象類具有以下特性:
●抽象類不能實例化。使用override關鍵字可在派生類中實現抽象方法,經override聲明重寫的方法,其簽名必須與override方法的簽名一致。
●抽象類可以包含抽象方法和抽象訪問器。
●不能用 sealed 修飾符修改抽象類,這意味着該類不能被繼承。
從抽象類派生的非抽象類必須包括繼承的所有抽象方法和抽象訪問器的實實現。
在方法或屬性聲明中使用 abstract 修飾符以指示此方法或屬性不包含實現。
抽象方法具有以下特性:
●抽象方法是隱式的 virtual 方法。
●只允許在抽象類中使用抽象方法聲明。
因爲抽象方法聲明不提供實實現,所以沒有方法體;方法聲明只是以一個分號結束,並且在簽名後沒有大括號 ({ })。例如:
public abstract void MyMethod();
●實現由 overriding 方法提供,它是非抽象類的成員。
●在抽象方法聲明中使用 static 或 virtual 修飾符是錯誤的。
除了在聲明和調用語法上不同外,抽象屬性的行爲與抽象方法一樣。
●在靜態屬性上使用 abstract 修飾符是錯誤的。
●在派生類中,通過包括使用 override 修飾符的屬性聲明可以重寫抽象的繼承屬性。
抽象類必須爲所有接口成員提供實現。即如果父類被聲明爲抽象類,並存在未實現的抽象方法,那麼子類就必須實現父類中所有的abstract成員,除非該類也是抽象的。
舉例:
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
/// <summary>
/// 抽象類hcedar
/// </summary>
abstract class hcedar
{
/// <summary>
/// 抽象方法SayHello
/// </summary>
abstract public void SayHello();
/// <summary>
/// 抽象屬性Hello
/// </summary>
abstract public string Hello
{
get;
set;
}
public void SayAbstract()
{
Console.WriteLine("this is a abstract!");
}
}
/// <summary>
/// hcedar2類,繼承hcedar
/// </summary>
class hcedar2 : hcedar
{
public string _hello;
/// <summary>
/// Hello屬性及其實現
/// </summary>
override public string Hello
{
get
{
return _hello;
}
set
{
_hello = value;
}
}
/// <summary>
/// SayHello方法及其實現
/// </summary>
override public void SayHello()
{
Console.WriteLine(Hello);
}
}
class Program
{
public static void Main()
{
hcedar2 h = new hcedar2();
h.Hello="Hello World!";
h.SayHello();
h.SayAbstract();
}
}
/*結果:
Hello World!
this is a abstract!
請按任意鍵繼續. . .
*/
}