[英]The difference between virtual, override, new and sealed override
我對 OOP 的一些概念感到很困惑: virtual
, override
, new
和 seal sealed override
。 誰能解釋這些差異?
我很清楚,如果要使用派生的 class 方法,可以使用override
關鍵字,這樣基本的 class 方法將被派生的 class 覆蓋。 但我不確定new
和sealed override
。
virtual關鍵字用於修改方法、屬性、索引器或事件聲明,並允許在派生的 class 中覆蓋它。 例如,此方法可以被任何繼承它的 class 覆蓋:使用 new 修飾符顯式隱藏從基 class 繼承的成員。 要隱藏繼承的成員,請在派生的 class 中使用相同的名稱聲明它,並使用 new 修飾符對其進行修改。
這都與多態性有關。 當在引用上調用虛擬方法時,引用所引用的 object 的實際類型用於決定使用哪個方法實現。 When a method of a base class is overridden in a derived class, the version in the derived class is used, even if the calling code didn't "know" that the object was an instance of the derived class. 例如:
public class Base
{
public virtual void SomeMethod()
{
}
}
public class Derived : Base
{
public override void SomeMethod()
{
}
}
...
Base d = new Derived();
d.SomeMethod();
如果覆蓋 Base.SomeMethod,最終將調用 Derived.SomeMethod。
現在,如果您使用new關鍵字而不是override ,則派生 class 中的方法不會覆蓋基本 class 中的方法,它只是隱藏它。 在這種情況下,代碼如下:
public class Base
{
public virtual void SomeOtherMethod()
{
}
}
public class Derived : Base
{
public new void SomeOtherMethod()
{
}
}
...
Base b = new Derived();
Derived d = new Derived();
b.SomeOtherMethod();
d.SomeOtherMethod();
將首先調用 Base.SomeOtherMethod,然后是 Derived.SomeOtherMethod。 它們實際上是兩個完全獨立的方法,它們恰好具有相同的名稱,而不是覆蓋基本方法的派生方法。
如果您未指定 new 或 overrides,則生成的 output 與您指定 new 時相同,但您也會收到編譯器警告(因為您可能不知道您在基礎 class 中隱藏了一個方法方法,或者實際上您可能想要覆蓋它,只是忘記包含關鍵字)。
覆蓋的屬性聲明可能包含sealed修飾符。 使用此修飾符可防止派生的 class 進一步覆蓋該屬性。 密封屬性的訪問者也被密封。
任何方法都可以是可覆蓋的(= virtual
)或不可覆蓋。 決定由定義方法的人做出:
class Person
{
// this one is not overridable (not virtual)
public String GetPersonType()
{
return "person";
}
// this one is overridable (virtual)
public virtual String GetName()
{
return "generic name";
}
}
現在您可以覆蓋那些可覆蓋的方法:
class Friend : Person
{
public Friend() : this("generic name") { }
public Friend(String name)
{
this._name = name;
}
// override Person.GetName:
public override String GetName()
{
return _name;
}
}
但是您不能覆蓋GetPersonType
方法,因為它不是虛擬的。
讓我們創建這些類的兩個實例:
Person person = new Person();
Friend friend = new Friend("Onotole");
當Fiend
實例調用非虛擬方法GetPersonType
時,實際上調用的是Person.GetPersonType
:
Console.WriteLine(friend.GetPersonType()); // "person"
當Friend
實例調用虛擬方法GetName
時,調用的是Friend.GetName
:
Console.WriteLine(friend.GetName()); // "Onotole"
當Person
實例調用虛擬方法GetName
時,調用的是Person.GetName
:
Console.WriteLine(person.GetName()); // "generic name"
當調用非虛擬方法時,不會查找方法體 - 編譯器已經知道需要調用的實際方法。 而虛擬方法編譯器無法確定調用哪一個,並且在運行時在 class 層次結構中從下到上從調用該方法的實例類型開始查找:對於friend.GetName
,它看起來開始在Friend
class 並立即找到它,對於person.GetName
class 它從Person
開始並在那里找到它。
有時您創建一個子類,覆蓋一個虛擬方法並且您不希望在層次結構中再有任何覆蓋 - 為此您使用sealed override
(假設您是最后一個覆蓋該方法的人):
class Mike : Friend
{
public sealed override String GetName()
{
return "Mike";
}
}
但有時你的朋友 Mike 決定改變他的性別,因此把他的名字改成 Alice :) 你可以改變原始代碼,或者改為子類 Mike:
class Alice : Mike
{
public new String GetName()
{
return "Alice";
}
}
在這里,您創建了一個完全不同的具有相同名稱的方法(現在您有兩個)。 調用哪種方法以及何時調用? 這取決於你如何稱呼它:
Alice alice = new Alice();
Console.WriteLine(alice.GetName()); // the new method is called, printing "Alice"
Console.WriteLine(((Mike)alice).GetName()); // the method hidden by new is called, printing "Mike"
當您從Alice
的角度調用它時,您調用Alice.GetName
,當從Mike
的角度調用時,您調用Mike.GetName
。 這里沒有進行運行時查找 - 因為這兩種方法都是非虛擬的。
您始終可以創建new
方法 - 無論您隱藏的方法是否為虛擬方法。
這也適用於屬性和事件——它們在下面表示為方法。
默認情況下,不能在派生的 class 中覆蓋方法,除非它被聲明為virtual
或abstract
。 virtual
表示在調用之前檢查較新的實現, abstract
表示相同,但保證在所有派生類中被覆蓋。 此外,在基本 class 中不需要實現,因為它將在其他地方重新定義。
上述情況的例外是new
修飾符。 可以在派生的 class 中使用new
修飾符重新定義未聲明為virtual
或abstract
的方法。 當在基礎 class 中調用該方法時,將執行基礎方法,而在派生 class 中調用該方法時,將執行新方法。 所有new
關鍵字允許您在 class 層次結構中使用兩個具有相同名稱的方法。
最后一個sealed
的修飾符打破了virtual
方法鏈,使它們不再被覆蓋。 這不經常使用,但選項在那里。 使用 3 個類的鏈更有意義,每個類都派生自前一個類
A -> B -> C
如果A
有一個在B
中被overridden
的virtual
或abstract
方法,那么它還可以通過在B
中聲明它sealed
防止C
再次更改它。
sealed
也用在classes
中,這就是你經常會遇到這個關鍵字的地方。
我希望這有幫助。
public class Base
{
public virtual void SomeMethod()
{
Console.WriteLine("B");
}
}
public class Derived : Base
{
//Same method is written 3 times with different keywords to explain different behaviors.
//This one is Simple method
public void SomeMethod()
{
Console.WriteLine("D");
}
//This method has 'new' keyword
public new void SomeMethod()
{
Console.WriteLine("D");
}
//This method has 'override' keyword
public override void SomeMethod()
{
Console.WriteLine("D");
}
}
現在第一件事
Base b=new Base();
Derived d=new Derived();
b.SomeMethod(); //will always write B
d.SomeMethod(); //will always write D
現在關鍵字都是關於多態性的
Base b = new Derived();
virtual
並在Derived
中覆蓋將給出 D(多態性)。Base
中使用沒有virtual
的override
會出錯。virtual
編寫方法(無覆蓋)將寫入帶有警告的“B”(因為沒有完成多態性)。Derived
中的那個簡單方法之前編寫new
。new
關鍵字是另一回事,它只是隱藏了警告,告訴您在基礎 class 中存在同名屬性。 virtual
或new
兩者都相同,除了new 修飾符
new
和override
不能在相同的方法或屬性之前使用。
sealed
或方法將其鎖定以用於派生 class 並給出編譯時錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.