簡單介紹虛函數virtual
在某基類中聲明 virtual 並在一個或多個派生類中被重新定義的成員函數稱為虛函數。
虛函數的作用就是實現多態性(Polymorphism),多態性是將接口與實現進行分離。
C#作為完全面向對象語言,所有函數並不默認為virtual,但可以在基類中聲明關鍵字virtual,就可以在其派生類中通過關鍵字override重寫該函數。重寫后的virtual函數依舊是virtual函數。由於virtual只對類中的實例函數成員有意義,所以成員字段和靜態函數都不能聲明為virtual,也不能與override和abstract一起用。
虛函數與一般函數的區別
一般函數在編譯時就靜態地編譯到了執行文件中,其相對地址在程序運行期間是不發生變化的,也就是寫死的!而虛函數在編譯期間是不被靜態編譯的,它的相對地址是不確定的,它會根據運行時期對象實例來動態判斷要調用的函數,其中聲明時定義的類叫聲明類,執行時實例化的類叫實例類。
使用虛函數virtual
1、當調用一個對象的函數時,系統會直接去檢查這個對象聲明定義的類,即聲明類,看所調用的函數是否為虛函數。
2、如果不是虛函數,那么它就直接執行該函數。而如果有virtual關鍵字,也就是一個虛函數,那么這個時候它就不會立刻執行該函數了,而是轉去檢查對象的實例類。
3、在這個實例類里,他會檢查這個實例類的定義中是否有重新實現該虛函數(通過override關鍵字),如果有,則馬上執行該實例類中的這個重新實現的函數。而如果沒有,系統會不停地往上找實例類的父類,並對父類重復剛才在實例類里的檢查,直到找到第一個重載了該虛函數的父類為止,然后執行該父類里重載后的函數。
實例:
運行結果:
常見面試題:
class Program { class A { public A() { PrintFields(); } public virtual void PrintFields() { } } class B : A { int x = 1; int y; public B() { y = -1; } public override void PrintFields() { Console.WriteLine("x={0},y={1}", x, y); } } static void Main(string[] args) { new B(); } }
問:當使用new B()創建B的實例時,產生什么輸出?
答:x=1,y=0
解析:創建B的實例,先隱式調用父類A的無參構造函數,執行PrintFields()方法,檢查到是虛方法,轉去檢查實例類B,有重載方法,執行重載方法,輸出x=1,y=0
注意:創建子類對象時會首先調用父類的構造函數,然后才會調用子類本身的構造函數,如果沒有指明要調用父類的哪一個構造函數,系統會隱式地調用父類的無參構造函數
End!