在面向對象程式設計中,有兩種截然不同的繼承方式:實作繼承和接口繼承。在實作繼承時候,在Java中,所有函數預設都是virtual的,而在C#中所有函數并不預設為virtual的,但可以在基類中通過聲明關鍵字virtual,就可以在其派生類中通過關鍵字override重寫該函數。
重寫後的virtual函數依舊是virtual函數。由于virtual隻對類中的執行個體函數成員有意義,是以成員字段和靜态函數都不能聲明為virtual,也不能與override和abstract一起用。C#中可以設定virtual屬性、索引器或事件。
無virtual和override關鍵字“重寫”
這是所謂的無virtual和override的“重寫”其實隻是隐藏。如果簽名後的函數在基類中都進行了聲明,卻沒有用virtual和override關鍵字,例如:
class Program
{
static void Main(string[] args)
{
A a1 = new A(); a1.Print();
A a2 = new B(); a2.Print();
A a3 = new C(); a3.Print();
Console.Read();
}
}
class A
{
public void Print()
{
Console.WriteLine("A");
}
}
class B : A
{
public void Print()
{
Console.WriteLine("B");
}
}
class C : B
{
public void Print()
{
Console.WriteLine("C");
}
}
//列印結果 A
A
A
有virtual和override關鍵字“重寫”
在派生類中添加關鍵字virtual和override,實作對基類的重寫:
class Program
{
static void Main(string[] args)
{
A a1 = new A(); a1.Print();
A a2 = new B(); a2.Print();
A a3 = new C(); a3.Print();
Console.Read();
}
}
class A
{
public void Print()
{
Console.WriteLine("A");
}
}
class B : A
{
public override void Print()
{
Console.WriteLine("B");
}
}
class C : B
{
public void Print()
{
Console.WriteLine("C");
}
}
//報錯
在類的定義中,申明時定義的類叫申明類,執行執行個體化時候定義的類叫執行個體類。
此時編譯器具體的檢查的流程如下
1、當調用函數時,系統會直接去檢查申明類,看所調用的函數是否為虛函數;
2、如果不是,那麼它就直接執行該函數。如果是virtual函數,則轉去檢查對象的執行個體類。
3.在執行個體類中,若有override的函數,則執行該函數,如果沒有,則依次上溯,按照同樣步驟對父類進行檢查,知道找到第一個override了此函數的父類,然後執行該父類中的函數。(星夢《C#虛函數virtual詳解收藏》)
class Program
{
static void Main(string[] args)
{
A a1 = new A(); a1.Print();
A a2 = new B(); a2.Print();
A a3 = new C(); a3.Print();
Console.Read();
}
}
class A
{
public virtual void Print()
{
Console.WriteLine("A");
}
}
class B : A
{
public override void Print()
{
Console.WriteLine("B");
}
}
class C : B
{
public void Print()
{
Console.WriteLine("C");
}
}
//列印結果 A
B
B
class Program
{
static void Main(string[] args)
{
A a1 = new A(); a1.Print();
A a2 = new B(); a2.Print();
A a3 = new C(); a3.Print();
Console.Read();
}
}
class A
{
public virtual void Print()
{
Console.WriteLine("A");
}
}
class B : A
{
public override void Print()
{
Console.WriteLine("B");
}
}
class C : B
{
public override void Print()
{
Console.WriteLine("C");
}
}
//列印結果 A
B
C