標籤:
C# 關鍵字--virtual
一、
virtual 關鍵字用於修飾方法、屬性、索引器或事件聲明,並使它們可以在衍生類別中被重寫。虛擬成員的實現可由衍生類別中的重寫成員更改,而非虛擬成員是無法由衍生類別進行重寫的,這一點是與Java不同的。Java語言中,只要在衍生類別中定義了與父類具有相同簽名的方法,那麼父類的方法就被重寫。C#語言中,必須使用virtual關鍵字進行修飾,否則在衍生類別中進行重寫會導致編譯器報錯。
虛方法或者虛屬性並不等同於抽象方法、抽象屬性。抽象方法和抽象屬性無法直接調用,必須通過衍生類別進行實現之後才能調用;而虛方法和虛屬性是表示在衍生類別中有可能進行重寫的,但是如果沒有重寫,那麼將調用父類中的該虛方法和虛屬性。調用虛方法時,將為重寫成員檢查該對象的運行時類型。將調用大部指派生類中的該重寫成員,如果沒有衍生類別重寫該成員,則它可能是原始成員。
預設情況下,方法是非虛擬,不能重寫非虛方法(除非使用new關鍵字)。virtual修飾符不能與static、abstract、private 或override修飾符一起使用。除了聲明和調用文法不同外,虛擬屬性的行為與抽象方法一樣。注意:
①在靜態屬性上使用 virtual 修飾符是錯誤的。
②通過包括使用 override修飾符的屬性聲明,可在衍生類別中重寫虛擬繼承屬性。
虛擬方法
若一個執行個體方法的聲明中含有 virtual修飾符,則稱該方法為虛擬方法。若其中沒有 virtual修飾符,則稱該方法為非虛擬方法。非虛擬方法的實現是不會變的:無論是在聲明它的類的執行個體上調用該方法還是在衍生類別的執行個體上調用,實現都是相同的。與此相反,一個虛擬方法的實現可以由衍生類別取代。取代所繼承的虛擬方法的實現的過程稱為重寫該方法。
classA
{
public void F() {Console.WriteLine("A.F"); }
public virtual voidG() { Console.WriteLine("A.G"); }
}
class B:A
{
newpublic void F() {Console.WriteLine("B.F"); }
public override void G() {Console.WriteLine("B.G"); }
}
class Test
{
static void Main(){
B b = newB();
A ab = b;//這裡a的類型是B類對象
A a = new A();
a.F(); //列印A.F
b.F(); //列印B.F
ab.F(); //列印A.F
a.G(); //列印B.G
b.G(); //列印B.G
ab.G(); //列印B.G
}
}
注意:從a.F()與ab.G()返回的結果可以看出,利用new和override關鍵字對方法進行重寫是有區別的。
- 基類對象調用基類對應的方法,不管是否是虛擬方法。
- 衍生類別對象分兩種情況
①引用聲明為衍生類別變數:調用衍生類別的方法
②引用聲明為基類變數:
■如果利用override重寫,那麼調用衍生類別中的重寫之後的方法。
■如果利用new重寫,那麼調用基類方法。
注意:上述原則對虛擬屬性同樣適用! 二、class A
{
public virtual void Func() // 注意virtual,表明這是一個虛擬函數
{
Console.WriteLine("Func In A");
}
}
class B : A // 注意B是從A類繼承,所以A是父類,B是子類
{
public override void Func() // 注意override ,表明重新實現了虛函數
{
Console.WriteLine("Func In B");
}
}
class C : B // 注意C是從B類繼承,所以B是父類,C是子類
{
}
class D : A // 注意D是從A類繼承,所以A是父類,D是子類
{
public new void Func() // 注意new ,表明覆蓋父類裡的同名類,而不是重新實現
{
Console.WriteLine("Func In D");
}
}
class Program
{
static void Main(string[] args)
{
A a; // 定義一個a這個A類的對象.這個A就是a的申明類
A b; // 定義一個b這個A類的對象.這個A就是b的申明類
A c; // 定義一個c這個A類的對象.這個A就是c的申明類
A d; // 定義一個d這個A類的對象.這個A就是d的申明類
a = new A(); // 執行個體化a對象,A是a的執行個體類
b = new B(); // 執行個體化b對象,B是b的執行個體類
c = new C(); // 執行個體化c對象,C是c的執行個體類
d = new D(); // 執行個體化d對象,D是d的執行個體類
a.Func(); // 執行a.Func:1.先檢查申明類A 2.檢查到是虛擬方法 3.轉去檢查執行個體類A,就為本身 4.執行執行個體類A中的方法 5.輸出結果 Func In A
b.Func(); // 執行b.Func:1.先檢查申明類A 2.檢查到是虛擬方法 3.轉去檢查執行個體類B,有重載的 4.執行執行個體類B中的方法 5.輸出結果 Func In B
c.Func(); // 執行c.Func:1.先檢查申明類A 2.檢查到是虛擬方法 3.轉去檢查執行個體類C,無重載的 4.轉去檢查類C的父類B,有重載的 5.執行父類B中的Func方法 5.輸出結果 Func In B
d.Func(); // 執行d.Func:1.先檢查申明類A 2.檢查到是虛擬方法 3.轉去檢查執行個體類D,無重載的(這個地方要注意了,雖然D裡有實現Func(),但沒有使用override關鍵字,所以不會被認為是重載) 4.轉去檢查類D的父類A,就為本身 5.執行父類A中的Func方法 5.輸出結果 Func In A
D d1 = new D();
d1.Func(); // 執行D類裡的Func(),輸出結果 Func In D
Console.ReadLine();
}
}
C# 關鍵字--virtual(轉)