2013-12-21 85 views
5

對於方法重寫和OOP原則的有效性,我有一個小混亂。 我知道所有關於密封,陰影,覆蓋,虛擬等,但我碰到一個場景,只是困惑我。假設我有:關於重寫規則的混淆C#

class classA 
{ 

    public virtual void sayhello() 

     { 
     Console.WriteLine("hello I'm A"); 
    } 

}; 

class classB :classA 
{ 
    public override void sayhello() 
    { 
     Console.WriteLine("hello I'm B"); 
    } 

}; 
class Program 
{ 
    static void Main(string[] args) 
    { 

     classB a = new classB(); 
     a.sayhello(); 
    } 
} 

據我迄今研究一切,一個方法聲明爲虛擬摘要(抽象類)可使用覆蓋關鍵字在子類中重寫。根據這個,上面的代碼工作完美。 當我除去虛擬關鍵字,然後嘗試使用覆蓋覆蓋關鍵字的方法,則編譯器給出誤差爲:

不能覆蓋繼承的成員「inheritence.classA.sayhello()」,因爲它是沒有標明虛擬,抽象或重寫

,然後我刪除了覆蓋關鍵詞,從子類,並提供了實現的:

class classB :classA 
{ 
    public void sayhello() 
    { 
     Console.WriteLine("hello I'm B"); 
    } 

}; 

在這種情況下,該方法可能會被覆蓋。我可以重寫該方法,它不是虛擬的或抽象的。所以,我的問題是:

1.它不違反OOP原則嗎?因爲我可以覆蓋該方法,該方法在父項中未標記爲虛擬

2.爲什麼我被允許以這種方式重寫該方法?甚至沒有標記虛擬

去除CLASSA方法虛擬關鍵字,它給了我密封方法的感覺CLASSA,當我試圖重寫方法CLASSB。 (正如我前面提到的編譯器錯誤)。如果我刪除虛擬,以便子類可能不會覆蓋它,那麼爲什麼孩子類可以巧妙地覆蓋它,刪除其覆蓋關鍵字?這是唯一的情況下,密封關鍵字是專爲?

+2

您執行了一種稱爲方法隱藏的概念http://msdn.microsoft.com/en-us/library/aa691135%28v=vs.71%29.aspx – Samuel

+0

是的,但是這不是違反了oop priciples嗎?比方說,classA不想讓它的方法被隱藏起來?或者爲什麼我們然後使用** new **關鍵字來進行遮蔽,當我們可以簡單地隱藏它時? – Zeeshan

+0

@ O.R.Mapper是的。因爲OP的實例類型爲'classB' –

回答

3

我想告訴你,你給隱藏的父子方法沒有被覆蓋。
一個你可能沒有注意到在做同樣的事情更是看到警告因爲在警告部分將被明確地表示,

警告「行號」 'classB .sayhello'皮繼承成員'classA.sayhello'。如果需要隱藏,請使用新的 關鍵字。

你的問題,

這是不是違反了OOP原則?因爲我可以覆蓋未在父級中標記爲虛擬的方法。

不確定它沒有違反OOP原則,因爲您隱藏了基類方法。

爲什麼我允許以這種方式重寫該方法?甚至沒有標記虛擬?

因爲C#不僅支持壓倒一切而且方法隱藏和A隱藏方法具有使用new關鍵字聲明。有關詳細信息,請閱讀dotnet_polymorphismoverriding-vs-method-hiding

難道這僅僅是個案,密封的關鍵字是專爲?

MSDN sealedsealed關鍵字被設計成防止類的推導和否定虛擬成員的虛擬方面。

  • 當應用於類時,密封修飾符會阻止其他類從其繼承。
  • 密封修飾符只能應用於覆蓋基類中的虛擬方法或屬性的方法或屬性。這會阻止進一步覆蓋特定的虛擬方法或屬性,但它永遠不會停止method-hiding。閱讀Non-overridable method獲取更多信息
+0

謝謝:)你能否讓我清楚,不是隱藏,間接等於重寫?爲什麼父類會讓它發生,當它不希望它的方法被覆蓋? – Zeeshan

+1

@Zeeshan查看已編輯的答案以獲取更多信息,並且您可以在[Sealed Overriden]中找到一些關於用'override'封裝的更有趣的想法(http://stackoverflow.com/questions/797530/c-sharp-is-它可能標記覆蓋方法作爲最終) – dbw

+0

你的意思是,我不能遮蔽密封的方法? – Zeeshan

1
  1. 它不違反OOP原則嗎?因爲我可以覆蓋未在父級中標記爲虛擬的方法。

你沒有overridemethod您已經隱藏父類的方法父。

所以你永遠不能從子類對象訪問父方法,因爲它是hidden你的子類method sayhello()

2.爲什麼我可以用這種方法覆蓋方法?甚至沒有標記虛擬?

因爲你可以用子實現隱藏父方法。

+0

謝謝。我可以肯定,我的孩子班級永遠不會以這種方式隱藏父母的方法嗎?因爲這似乎是一件危險的事情。 – Zeeshan

+1

@Zeeshan:唯一的可能性是檢查警告:'警告'classB.sayhello()'隱藏繼承成員'classA.sayhello()'。如果需要隱藏,請使用新關鍵字。 \t ' –

1

我認爲這是來自C++實現,它使用了切片(What is object slicing?)。儘管C#與大多數Java類似,但在某些情況下(這一點和值類型的存在),它遵循C++方式。

此後的推理是,由於您的代碼調用A變量的方法sayhello,程序員期望執行A.sayhello的邏輯。它不會破壞OOP原則,因爲您正在執行A.sayhello實施(所以它必須匹配A.sayhello合同)。

與Java的差不OOP VS不OOP,但Java使用late binding(要被執行以基於在a實際實例的運行時決定的實際方法),而C#使用early binding(該方法是在編譯時決定)除非該方法是虛擬的。

我個人更喜歡後期綁定,而從OOP的角度來看,C#方法是正確的,我發現通常應該使用更專門化的方法。

+0

另外檢查http:// stackoverflow。com/questions/367411/early-binding-vs-late-binding-what-are-the-comparative-benefits-and-unfavanta – SJuan76

+0

非常好的解釋和區分:) – Zeeshan

+0

請注意,** a **是一個對象classB。抱歉不要讓它混淆。 – Zeeshan

1

那麼,它到底很簡單:

  1. 當重寫虛擬方法,具體方法是在運行時解決
  2. 當使用new關鍵字(或完全保留)時,根據代碼中可用的類型信息,在編譯時處執行靜態替換操作。

這兩個完全不同的東西。

+0

謝謝。你是說當我隱藏方法的實現時,這種情況下的解析實際上是在運行時? – Zeeshan

+0

不,反過來說:覆蓋意味着在運行時解析,方法隱藏發生在編譯時。 –

+0

重寫始終在運行時解決?即使它是靜態綁定,並在代碼中0%多態效應? – Zeeshan

1

你所做的是方法隱藏(正如其他人已經解釋過的)。

如果您確實想要這樣做,您應該在方法定義中添加新的關鍵字以使警告消失並且還可以作爲文檔。所以看着你的代碼的其他開發人員知道你是故意的。