粗略的看一下,感覺實現接口和虛函數重載是一樣的。你定義了一些對象, 但是這些對象是在另一個類型裡申明的。你被第一感覺騙了,實現接口與虛函數 重載是完全不同的。在接口裡定義的成員默認情況下,是根本不存在實際內容的 。
派生類不能重載基類中的接口成員。接口可以隱式的實現,就是把它 們從類的公共接口中隱藏。它們的概念是不同的而且使用也是不同的。
但你可以這樣的實現接口:讓你的派生類可以修改你的實現。你只用對派生類做 一個Hook就行了。(譯注:相信寫過C++程序的人就知道hook是什麼意思,而且我 也實在想不到把hook譯成什麼比較好,所以就直接用hook這個原詞了,就像bug 一樣。)
為了展示它們的不同之處,試著做一個簡單的接口以及在一個類 中實現它:
interface IMsg
{
void Message();
}
public class MyClass : IMsg
{
public void Message()
{
Console.WriteLine( "MyClass" );
}
}
Message()方法是MyClass的公共接口, Message同樣可以用一個接口指針IMsg來訪問。現在讓我們來一點繁雜的,添加 一個派生類:
public class MyDerivedClass : MyClass
{
public new void Message()
{
Console.WriteLine( "MyDerivedClass" );
}
}
注意到,我添加了一個關鍵字new在Message方法上,用於區別前 面的一個Message(參見原則29)。MyClass.Message()不是虛函數,派生類可以不 提供重載版本。MyDerived類創建了一個新的Message方法,但這個方法並不是重 載MyClass.Message:它隱藏了原來的方法。而且,MyClass.Message還是可以通 過IMsg的引用來訪問:
MyDerivedClass d = new MyDerivedClass( );
d.Message( ); // prints "MyDerivedClass".
IMsg m = d as IMsg;
m.Message( ); // prints "MyClass"
接口方法不是虛的,當你實 現一個接口時,你就要在詳細的相關類型中申明具體的實現內容。
但你 可能想要創建接口,在基類中實現這些接口而且在派生類中修改它們的行為。這 是可以辦法到的。你有兩個選擇,如果不訪問基類,你可以在派生類中重新實現 這個接口:
public class MyDerivedClass : MyClass, IMsg
{
public new void Message()
{
Console.WriteLine( "MyDerivedClass" );
}
}
添加的IMsg讓你的派生類的行為發生了改變,以至IMsg.Message 現在是在派生類上使用的:
MyDerivedClass d = new MyDerivedClass( );
d.Message( ); // prints "MyDerivedClass".
IMsg m = d as IMsg;
m.Message( ); // prints "MyDerivedClass"
派生類上還是須要 在MyDerivedClass.Message()方法上添加關鍵字new,這還是有一點隱患(參見原 則29)。基類還是可以通過接口引用來訪問:
MyDerivedClass d = new MyDerivedClass( );
d.Message( ); // prints "MyDerivedClass".
IMsg m = d as IMsg;
m.Message( ); // prints "MyDerivedClass"
MyClass b = d;
b.Message( ); // prints "MyClass"
唯一可以修 正這個問題的方法是修改基類,把接口的申明修改為虛函數:
public class MyClass : IMsg
{
public virtual void Message()
{
Console.WriteLine( "MyClass" );
}
}
public class MyDerivedClass : MyClass
{
public override void Message()
{
Console.WriteLine( "MyDerivedClass" );
}
}
MyDerivedClass以及其它所有從MyClass派生的類 可以申明它們自己的Message()方法。這個重載的版本每次都會調用:通過 MyDerivedClass的引用,通過IMsg接口的引用,或者直接通過MyClass的引用。
如果你不喜歡混雜的虛函數概念,那就對MyClass的定義做一個小的修改 :
public abstract class MyClass, IMsg
{
public abstract void Message();
}
是的,你可以用一個 抽象方法來實現一個接口。通過申明一個接口內的抽象的方法,你可以讓你的所 有派生都必須實現這個接口。現在,IMsg接口成為了MyClass的一個組成部份, 你的每一個派生類都必須實現它。
隱式接口實現,可以讓你在一個類上 隱藏公共的接口成員方法,而且也實現了這個接口。它在實現接口和虛函數重載 上繞了幾個圈。當有多個合適的函數版本時,你可以利用隱式接口的實現來限制 用戶的編碼。在原則26講到的IComparable習慣會詳細的討論這一點。
實 現接口讓我們有更多的選擇,用於創建和重載虛函數。你可以創建隱秘的實現, 虛的實現,或者抽象關聯到派生類。你可以精確的決定,你的派生類如何以及何 時,修改接口的默認實現。接口方法不是虛方法,而是一個獨立的約定!
返回教程目錄