首先,看下面的代碼。
namespace CSharpTest
{
class A
{
public void fun()
{
Console.WriteLine("這是父類方法");
}
}
class B : A
{
public void fun()
{
Console.WriteLine("這是子類方法");
}
}
class Test
{
public static void Main()
{
A a = new A();
a.fun();
a = new B();
a.fun();
}
}
}
猜猜結果是什麼?
如果對Java熟悉的朋友,可能會認為是結果:
這是父類方法
這是子類方法
但是其實運行結果是:
這是父類方法
這是父類方法
這是因為Java中的類方法默認是虛函數(雖然Java中沒有這個叫法),子類函數會默認覆蓋父類的同名函數(Java後來提供了@override注解)。然而C#中必須使用virtual關鍵字顯示聲明該函數是虛函數,然後在子類中使用override關鍵字重寫父類方法,這才真正實現了對父類方法的重寫,才能實現多態(C++中的多態就是使用虛函數實現的,而且和C#一樣必須使用virtual關鍵字顯示聲明)。
所以,要輸出結果為:
這是父類方法
這是子類方法
需要修改代碼如下:
namespace CSharpTest
{
class A
{
public virtual void fun()
{
Console.WriteLine("這是父類方法");
}
}
class B : A
{
public override void fun()
{
Console.WriteLine("這是子類方法");
}
}
class Test
{
public static void Main()
{
A a = new A();
a.fun();
a = new B();
a.fun();
}
}
}
即給父類的方法添加virtual關鍵字,給子類的同名方法添加override關鍵字。
首先看下面的代碼:
namespace CSharpTest
{
class C
{
public virtual void fun()
{
Console.WriteLine("這是一個虛方法");
}
}
class C1 : C
{
public override void fun()
{
Console.WriteLine("使用override關鍵字修飾的方法");
}
}
class C2 : C
{
public new void fun()
{
Console.WriteLine("使用new關鍵字修飾的方法");
}
}
class Test
{
public static void Main()
{
C c1 = new C1();
c1.fun();
C c2 = new C2();
c2.fun();
}
}
}
猜猜上面的代碼輸出結果?
正確的結果是:
使用override關鍵字修飾的方法
這是一個虛方法
為什麼使用關鍵字new修飾的方法,調用的是父類的方法呢?
是不是很奇怪?為什麼使用override關鍵字的子類方法被調用了,而使用new關鍵字的子類方法沒有被調用。
首先看看override關鍵字:override方法為從基類繼承的成員提供新的實現。以override聲明重寫的方法被稱為被重寫的基類方法,被重寫的基類方法必須具有與重寫方法相同的簽名。非虛方法或者靜態方法不能被重寫,被重寫的基類必須是virtual、abstract或者override的。override聲明不能改變虛方法的可訪問性,override方法和virtual方法必須具有相同的訪問級別修飾符。不能使用下列修飾符修飾重寫方法:new、static、virtual和abstract。
new關鍵字:new修飾符用來明確地隱藏由基類繼承而來的成員。要隱藏繼承而來的成員,可以在派生類中共用相同的名稱並用new修飾符修飾它。
下面來分析我們的程序:
c1.fun();因為子類C1使用override關鍵字重寫了父類的方法,基類C和子類C1都具有fun()方法,所以c1.fun()會動態調用C1的fun()方法而不是父類的。
c2.fun();子類C2使用new關鍵字隱藏了父類的方法,相當於子類中的fun()方法是直接繼承自父類的。而子類中使用new關鍵字聲明的fun()方法是另一個方法,只是恰巧與子類的fun()方法同名而已(是不是有些糊塗了)。所以 c2.fun()會調用父類的fun()方法,要想調用C2的fun()方法必須吧c2強制轉換為C2.
下面看看微軟官方的文檔解釋:
C# 語言經過專門設計,以便不同庫中的基類與派生類之間的版本控制可以不斷向前發展,同時保持向後兼容。這具有多方面的意義。例如,這意味著在基類中引入與派生類中的某個成員具有相同名稱的新成員在 C# 中是完全支持的,不會導致意外行為。它還意味著類必須顯式聲明某方法是要重寫一個繼承方法,還是一個隱藏具有類似名稱的繼承方法的新方法。
在 C# 中,派生類可以包含與基類方法同名的方法。
基類方法必須定義為 virtual。
如果派生類中的方法前面沒有 new 或 override 關鍵字,則編譯器將發出警告,該方法將有如存在 new 關鍵字一樣執行操作。
如果派生類中的方法前面帶有 new 關鍵字,則該方法被定義為獨立於基類中的方法。
如果派生類中的方法前面帶有 override 關鍵字,則派生類的對象將調用該方法,而不是調用基類方法。
可以從派生類中使用 base 關鍵字調用基類方法。
override、virtual 和 new 關鍵字還可以用於屬性、索引器和事件中。
默認情況下,C# 方法為非虛方法。如果某個方法被聲明為虛方法,則繼承該方法的任何類都可以實現它自己的版本。若要使方法成為虛方法,必須在基類的方法聲明中使用 virtual 修飾符。然後,派生類可以使用 override 關鍵字重寫基虛方法,或使用 new 關鍵字隱藏基類中的虛方法。如果 override 關鍵字和 new 關鍵字均未指定,編譯器將發出警告,並且派生類中的方法將隱藏基類中的方法。