2011-05-18 57 views
5

我性學習的C#(C++背景),所以我來翻過這段代碼:C#接口和繼承問題

public interface IUndoable { void Undo(); } 
public class TextBox : IUndoable 
{ 
    void IUndoable.Undo() { Console.WriteLine ("TextBox.Undo"); } 
} 

public class RichTextBox : TextBox, IUndoable 
{ 
    public new void Undo() { Console.WriteLine ("RichTextBox.Undo"); } 
} 

由於RichTextBox的從文字框派生,任何人都可以解釋爲什麼RichTextBox中也從IUndoable派生?。我會認爲IUndoable接口將與RichTextBox有權訪問的任何其他TextBox成員「繼承」?另外,我從我迄今爲止讀過的內容中猜測,公共,受保護和私有繼承的概念在C#中不存在。

這是一個正確的推論嗎?如果是這樣,這種行爲(即限制繼承)如何在C#中實現?

[編輯]

澄清:在這本書我讀的部分是關於的細微差別和隱式和顯式接口實現的潛在陷阱 - 所以我明白了。此外,代碼片段(從書中複製)有意爲之,以便解釋由於調用基類中隱式實現的重新實現的成員方法而產生的不同語義(phew!)。

我的主要問題可以簡單地概括爲:

難道這:

public class RichTextBox : TextBox, IUndoable 
{ 
    public new void Undo() { Console.WriteLine ("RichTextBox.Undo"); } 
} 

可以寫成:

public class RichTextBox : TextBox 
{ 
    public new void Undo() { Console.WriteLine ("RichTextBox.Undo"); } 
} 

,如果是,爲什麼作者是冗長(他我肯定有一個理由)。 如果不是,爲什麼界面不是從TextBox繼承的?

+1

請參閱http://msdn.microsoft.com/en-us/library/ms173153(v=vs.80).aspx瞭解何時使用覆蓋和新關鍵字。 – nickvane 2011-05-18 07:16:54

回答

1

RichTextBox將不必明確指定IUndoable。像ReSharper這樣的工具甚至可能會告訴你,並提供刪除。

而AFAIK對繼承沒有限制,只是「默認」繼承。

如果你不想讓人從你的班級派生出來,請將它設爲sealed

6

在C#中,對於類,在C++中只有公共繼承的等價物。

但是,您可以明確地實現接口明確隱含地。文本框實現IUdoable明確的,這就是爲什麼你在TextBox類有

void IUndoable.Undo() 

而不是簡單地

void Undo() 

。當接口顯式實現,只能通過顯式轉換訪問接口的對象上的方法:

TextBox tb = new TextBox(); 
tb.Undo(); // error 
((IUndoable)tb).Undo(); // ok 

接口方面,像你說的,「一起繼承」,但RichTextBox中重新器具IUndoable含蓄,所以你不需要投訪問接口的方法:

RichTextBox rtb = new RichTextBox(); 
rtb.Undo(); // ok 
0

其實RichTextBox中推出的Undo方法,而不是覆蓋它一個新的行爲(新的關鍵字顯示此),因此如果使用它的默認界面訪問的RichTextBox這個方法會被執行,但是如果使用它的父接口訪問TextBox的Undo方法將會是執行.RichTextBox明確地實現了IUndoable,所以如果任何人想使用IUndoable接口到達這個類,新的方法將被執行。 總結:

var obj=new RichTextBox(); 

    obj.Undo(); // hits the new method 
    ((TextBox)obj).Undo(); //hits the parent (old) method. 
    ((IUndoable)obj).Undo(); //hits the new method if RichTextBox implements IUndoable and otherwise hits the old method 

這不是一個好方法,因爲自撤銷尚未被定義爲父類中的虛就意味着它不打算overrided,我們通過引入這種新的方法打破了繼承層次。

0

是的,它可能是,它也越來越編譯

public class IUndoable 
{ 
} 
public class TextBox : IUndoable 
{ 
    public new void Undo() { Console.WriteLine ("RichTextBox.Undo"); } 
} 

public class RichTextBox : TextBox 
{ 
    public new void Undo() { Console.WriteLine ("RichTextBox.Undo"); } 
} 
0

你是正確的。 RichtTextBox也不一定需要執行IUndoable。由於RichTextBox中的Undo方法隱藏了文本框的Undo方法(請參閱new關鍵字),您可以看到編譯器也不是很高興。

當子類應該實現其基類的接口時,唯一的原因是這些類是ComVisible,並且您想將該接口公開給COM。

2

運行一個快速示例顯示差異。

interface IUndoable 
{ 
    void Undo(); 
} 

class TextBox : IUndoable 
{ 
    void IUndoable.Undo() 
    { 
     Console.WriteLine("TextBox.Undo"); 
    } 
} 

class RichTexBox : TextBox 
{ 
    public new void Undo() 
    { 
     Console.WriteLine("RichTextBox.Undo"); 
    } 
} 

class FilthyRichTextBox : TextBox, IUndoable 
{ 
    public new void Undo() 
    { 
     Console.WriteLine("FilthyRichTextBox.Undo"); 
    } 
} 

運行以下命令:

IUndoable text = new TextBox(); 
IUndoable richText = new RichTexBox(); 
IUndoable filthyRichText = new FilthyRichTextBox(); 

Console.WriteLine("From the TextBox:"); 
text.Undo(); 

Console.WriteLine("From the RichTextBox:"); 
richText.Undo(); 

Console.WriteLine("From the FilthyRichTextBox:"); 
filthyRichText.Undo(); 

下面是結果:


從文本框:
TextBox.Undo
從RichTextBox的:
TextBox.Undo
從FilthyRichTextBox:
FilthyRichTextBox.Undo