.net框架读书笔记---虚方法
接上一篇.net框架讀書筆記---引用參數(ref/out),
一、虛方法調用機理
代碼 namespace VirtualFunction
{
class Program
{
static void Main(string[] args)
{
SomeBaseClass sbc = new SomeClass();
sbc.SomeFun();
SomeBaseClass sbcOwn = new SomeBaseClass();
sbcOwn.SomeFun();
SomeClass sc = new SomeClass();
sc.SomeFun();
}
}
public class SomeBaseClass
{
public virtual void SomeFun()
{
Console.WriteLine("Base");
}
}
public class SomeClass : SomeBaseClass
{
public override void SomeFun()
{
Console.WriteLine("inherited");
}
}
}
上面代碼展示了,對于虛方法的調用。
通過檢查元數據,CLR可以確定一個非靜態方法是否為一個虛方法。然而,CLR在調用方法時并不使用該信息,CLR提供了兩個IL指令來調用方法:call和callvirt.其中call指令根據引用變量的類型(引用變量的動態類型,實際類型)來調用一個方法,而callvirt指令根據引用變量的對象類型來調用一個方法。當編譯源代碼時,編譯器知道代碼是否在調用一個虛方法,并根據此產生call和callvirt指令。
不管最終通過call還是callvirt來調用一個實例方法,所有的實例方法都會接受一個隱藏的this 指針作為方法d哦第一個參數。其中this指針指向當前正在操作的對象。
二、虛方法的版本問題
假設CompanyA設計一個類型Phone。
namespace CompanyA{
class Phone
{
public void Dial()
{
Console.WriteLine("Phone.Dial");
}
}
}
?
再假設CompanyB使用CompanyA的Phone作為基類又定義了一個類型BetterPhone。
代碼 namespace CompanyB{
class BetterPhone : CompanyA.Phone
{
public void Dial()
{
Console.WriteLine("BetterPhone.Dial");
EstablishConnection();
base.Dial();
}
protected virtual void EstablishConnection()
{
Console.WriteLine("BetterPhone.EstablishConnection");
}
}
}
?
當編譯以上代碼時會爆出警告“Warning?1?'CompanyB.BetterPhone.Dial()' hides inherited member 'CompanyA.Phone.Dial()'. Use the new keyword if hiding was intended.”,該警告告知開發人員BetterPhone中在定義Dial方法會隱藏Phone中的Dial方法。編譯器還告知我們通過在BetterPhone類的Dial定義前添加new關鍵字可以消除這種警告。修正后:
代碼 namespace CompanyB{
class BetterPhone : CompanyA.Phone
{
public new void Dial()
{
Console.WriteLine("BetterPhone.Dial");
EstablishConnection();
base.Dial();
}
protected virtual void EstablishConnection()
{
Console.WriteLine("BetterPhone.EstablishConnection");
}
}
}
?
上面代碼警告消失。上面代碼演示了對于非虛方法的版本控制。
虛方法的版本控制其實是一樣的,假設CompanyA也增加虛方法,看下面代碼
代碼 namespace CompanyA{
class Phone
{
public void Dial()
{
Console.WriteLine("Phone.Dial");
EstablishConnection();
}
protected virtual void EstablishConnection()
{
Console.WriteLine("Phone.EstablishConnection");
}
}
}
保持CompanyB的方法不要改變,編譯后仍然會出現上面的警告,解決辦法在CompanyB的虛方法前面增加new關鍵字:
代碼 namespace CompanyB{
class BetterPhone : CompanyA.Phone
{
public new void Dial()
{
Console.WriteLine("BetterPhone.Dial");
EstablishConnection();
base.Dial();
}
protected new virtual void EstablishConnection()
{
Console.WriteLine("BetterPhone.EstablishConnection");
}
}
}
ps:new關鍵字告訴編譯器,子類中的方法雖然與父類方法一樣(簽名,參數),但是該方法與基類中的方法沒有任何關系。
也有另外一種情況,CompanyB可能在得到CompanyA新版本后,認為COmpany。Phone的Dial和EstablishConnection是其期望的,那么CompanyB.BetterPhone可以完全刪除BetterPhone中的Dial方法,由于CompanyB希望告知編譯器BetterPhone中的EstablistConnnection和Phone中的EstablishConnection是相關聯的,那么new關鍵字必須要去掉,還需要將BetterPhone的virtual變為override(重寫),如下:
代碼 namespace CompanyB{
class BetterPhone : CompanyA.Phone
{
//刪除Dial方法,直接從基類繼承Dial
//刪除new并將virtual修改為override
//該方法將和基類的EstablishConnection建立聯系
protected override void EstablishConnection()
{
Console.WriteLine("BetterPhone.EstablishConnection");
}
}
}
有興趣,大家可以看看下面執行的結果是什么。
代碼 namespace VirtualFunction{
class Program
{
static void Main(string[] args)
{
Base bsA = new InheritedA();
bsA.Fun();//??
Base bsB = new InheritedB();
bsB.Fun();//??
}
}
class Base
{
public virtual void Fun()
{
Console.WriteLine("BaseFun");
}
}
class InheritedA :Base
{
public new void Fun()
{
Console.WriteLine("InteritedFunA");
}
}
class InheritedB : Base
{
public override void Fun()
{
Console.WriteLine("InteritedFunB");
}
}
}
??處的輸出時什么
轉載于:https://www.cnblogs.com/sanjia/archive/2010/05/02/1726034.html
總結
以上是生活随笔為你收集整理的.net框架读书笔记---虚方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JAVA中equals()方法的重要性
- 下一篇: 做人真善美,做事拖后腿