在上面程序的上下文中,我們要向C#新手多做一點解釋。
我們能夠使基類的一個對象和派生類xxx的一個對象相等。我們調用了方法a.abc()。隨之出現的 問題是,函數abc的下列2個版本,哪個將會被調用?
l 出現在基類yyy中的函數abc,調用對象屬 於這個函數。
或
l 函數abc存在於類xxx中,它會被初始化為這個類型。
換句話說 ,是編譯期間類型有意義,還是運行期間的類型有意義?
基類函數具有一個名為virtual的修飾符 ,暗示了派生類能覆寫這個函數。派生類,通過添加修飾符new,通知編譯器——這個函數abc 與派生類的函數abc無關。它會把它們當作單獨的實體。
首先,使用ldloc.0把this指針放到棧上 ,而不是使用call指令。這裡有一個callvirt作為替代。這是因為函數abc是虛的。除此之外,沒有區別 。類yyy中的函數abc被聲明為虛的,還被標記為newslot。這表示它是一個新的虛函數。關鍵字new位於C# 的派生類中。
IL還使用了類似於C#的機制,來斷定哪個版本的abc函數會被調用。
a.cs
class zzz
{
public static void Main()
{
yyy a = new xxx();
a.abc();
}
}
class yyy
{
public virtual void abc()
{
System.Console.WriteLine("yyy abc");
}
}
class xxx : yyy
{
public override void abc()
{
System.Console.WriteLine("xxx abc");
}
}
a.il
.assembly mukhi {}
.class private auto ansi zzz extends [mscorlib]System.Object
{
.method public hidebysig static void vijay() il managed
{
.entrypoint
.locals (class yyy V_0)
newobj instance void xxx::.ctor()
stloc.0
ldloc.0
callvirt instance void yyy::abc()
ret
}
}
.class private auto ansi yyy extends [mscorlib]System.Object
{
.method public hidebysig newslot virtual instance void abc() il managed
{
ldstr "yyy abc"
call void [mscorlib]System.Console::WriteLine(class System.String)
ret
}
}
.class private auto ansi xxx extends yyy
{
.method public hidebysig virtual instance void abc() il managed
{
ldstr "xxx abc"
call void [mscorlib]System.Console::WriteLine(class System.String)
ret
}
.method public hidebysig specialname rtspecialname instance void .ctor() il managed
{
ldarg.0
call instance void yyy::.ctor()
ret
}
}
Output
xxx abc