目錄:
- 一、虛方法的概念
- 二、虛方法的特點
- 三、虛方法的作用
- 四、虛方法的聲明
- 五、虛方法的執行
- 六、虛擬類的規則
一、虛方法的概念
在C#中,虛方法就是可以被子類重寫的方法,如果子類重寫了虛方法,則在運行時將運行重寫的邏輯;如果子類沒有重寫虛方法,則在運行時將運行父類的邏輯。虛函數在編譯期間是不被靜態編譯的,它的相對地址是不確定的,它會根據運行時期對象實例來動態判斷要調用的函數,其中那個申明時定義的類叫申明類,那個執行時實例化的類叫實例類。虛方法是用virtual關鍵字聲明的
A a = new B(); 其中A是申明類,B是實例類。
二、虛方法的特點
- 虛方法前不允許有static,abstract,或override修飾符(因為靜態的方法和抽象方法不能重寫)
- 虛方法不能是私有的(因為在子類中要進行重寫),所以不能使用private修飾符
- 不能在聲明虛方法的同時指定重寫虛方法,因為重寫方法只能重寫基類的虛方法,也就是要提前在基類中聲明虛方法,所以virtual關鍵字和override關鍵字不能同時使用。
三、虛方法的作用
- 允許派生類(即其子類)對父類進行擴展。
- 虛方法是多態特性的一種體現。
- 增加開發過程中的可維護性,條理清晰明了。
四、虛方法的聲明
在父類中:
1
2 3 4 |
public virtual 返回類型 方法名()
{ 方法體; } |
在子類中:
1
2 3 4 5 |
public override 返回值類型 方法名()
{ base.父類方法; 方法體; } |
五、虛方法的執行
一般方法在編譯時就靜態地編譯到了執行文件中,其相對地址在程序運行期間是不發生變化的,也就是寫死了的!
虛函數在編譯期間是不被靜態編譯的,它的相對地址是不確定的,它會根據運行時期對象實例來動態判斷要調用的函數。
具體的檢查流程如下:
- 當調用一個對象的方法時,系統會直接去檢查這個對象申明定義的類,即申明類,看所調用的方法是否為虛方法。
- 如果不是虛函數,那么它就直接執行該函數。如果有virtual關鍵字,也就是一個虛方法,那么這個時候它就不會立刻執行該函數了,而是轉去檢查對象的實例類。
- 在這個實例類里,它會檢查這個實例類的定義中是否有實現該虛方法(通過new關鍵字)或是否有重新實現該虛方法(通過override關鍵字),如果有,那么OK,它就不會再找了,而馬上執行該實例類中的這個重新實現的方法。而如果沒有的話,系統就會不停地往上找實例類的父類,並對父類重復剛才在實例類里的檢查,直到找到第一個重載了該虛方法的父類為止,然后執行該父類里重載后的方法。
下面我們通過具體實例看看:
例1:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class A
{ public virtual void Getreturn() { Console.WriteLine("我是A類的虛方法"); } } class Program { static void Main(string[] args) { A a = new A();//定義一個a這個A類的對象,這個A就是a的申明類,實例化a對象,A是a的實例類 a.Getreturn(); Console.ReadLine(); } } |
過程:1.先檢查申明類A 2.檢查到是Getreturn是虛擬方法 3.轉去檢查實例類A,結果是它本身 4.執行實例類A中實現Getreturn的方法 5.輸出結果我是A類的虛方法
例2:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class A
{ public virtual void Getreturn() { Console.WriteLine("我是A類的虛方法"); } } class B : A { public override void Getreturn() //重新實現了虛方法 { Console.WriteLine("我是B類重寫后的方法"); } } class Program { static void Main(string[] args) { A a = new B();//定義一個a這個A類的對象,這個A就是a的申明類,實例化a對象,B是a的實例類 a.Getreturn(); Console.ReadLine(); } } |
過程:1.先檢查申明類A 2.檢查到是虛擬方法 3.轉去檢查實例類B,有重寫的方法 4.執行實例類B中的方法 5.輸出結果我是B類重寫后的方法
例3:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class A
{ public virtual void Getreturn() { Console.WriteLine("我是A類的虛方法"); } } class B : A { public override void Getreturn() //重新實現了虛方法 { Console.WriteLine("我是B類重寫后的方法"); } } class C : B { } class Program { static void Main(string[] args) { A a = new C();//定義一個a這個A類的對象,這個A就是a的申明類,實例化a對象,C是a的實例類 a.Getreturn(); Console.ReadLine(); } } |
過程:1.先檢查申明類A 2.檢查到是虛擬方法 3.轉去檢查實例類C,無重寫的方法 4.轉去檢查類C的父類B,有重寫的方法5.執行父類B中的Getreturn方法 6.輸出結果我是B類重寫后的方法
例4:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class A
{ public virtual void Getreturn() { Console.WriteLine("我是A類的虛方法"); } } class B : A { public new void Getreturn() //覆蓋父類里的同名函數,而不是重新實現 { Console.WriteLine("我是B類New方法"); } } class Program { static void Main(string[] args) { A a = new B();//定義一個a這個A類的對象,這個A就是a的申明類,實例化a對象,B是a的實例類 a.Getreturn(); Console.ReadLine(); } } |
過程:1.先檢查申明類A 2.檢查到是虛擬方法 3.轉去檢查實例類B,無重寫的(這個地方要注意了,雖然B里有實現Getreturn(),但沒有使用override關鍵字,所以不會被認為是重寫) 4.轉去檢查類B的父類A,就是它本身 5.執行父類A中的Getreturn方法 6.輸出結果我是A類的虛方法
例5:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class A
{ public virtual void Getreturn() { Console.WriteLine("我是A類的虛方法"); } } class B : A { public new void Getreturn() //覆蓋父類里的同名函數,而不是重新實現 { Console.WriteLine("我是B類New方法"); } } class Program { static void Main(string[] args) { B b = new B();//定義一個b這個B類的對象,這個B就是b的申明類,實例化b對象,B是b的實例類 b.Getreturn(); Console.ReadLine(); } } |
過程:1.先檢查申明類B 2.檢查到不是虛擬方法 3.執行B類里的Getreturn() 4.輸出結果我是B類New方法
可以使用抽象方法重寫基類中的虛方法
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class A
{ public virtual void Getreturn() { Console.WriteLine("A類的虛方法"); } } abstract class B : A { public abstract override void Getreturn();//使用override修飾符,表示抽象重寫了基類中該函數的實現 } abstract class C : A { public abstract new void Getreturn();//使用new修飾符顯式聲明,表示隱藏了基類中該函數的實現 } |
密封類可以重寫基類中的虛方法(基類中的虛方法將隱式的轉化為非虛方法,但密封類本身不能再增加新的虛方法)
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class A
{ public virtual void Getreturn() { Console.WriteLine("A類的虛方法"); } } sealed class Program:A { public override void Getreturn() { Console.WriteLine("Program類重寫后的方法"); } static void Main(string[] args) { Program p = new Program(); p.Getreturn(); Console.ReadLine(); } } |
虛方法和new
new關鍵用於隱藏父類的成員,所有可以用new關鍵字隱藏父類的虛擬方法。
abstract和虛擬方法
抽象方法是隱式的虛擬方法,所有抽象類的非抽象子類可以用new 和override關鍵來重寫abstract 方法