Разница между виртуальным, переопределенным, новым и запечатанным переопределением
Я довольно запутался между некоторыми понятиями ООП:virtual,override,new и sealed override. Кто-нибудь может объяснить разницу?
Я довольно ясно, что если метод производного класса должен использоваться, можно использовать override ключевое слово, чтобы метод базового класса был переопределен производным классом. Но я не уверен насчет new и sealed override.
4 ответа:
The виртуальный ключевое слово используется для изменения метода, свойства, индексатора или объявления события и позволяет переопределить его в производном классе. Например, этот метод может быть переопределен любым производным классом: Используйте новый модификатор, чтобы явно скрыть элемент, унаследованный от базового класса. Чтобы скрыть унаследованный член, объявите его в производном классе с тем же именем и измените его с помощью нового модификатора.
Это все связано с полиморфизмом. Когда виртуальный метод вызывается по ссылке, фактический тип объекта, на который ссылается ссылка, используется для определения того, какую реализацию метода использовать. Когда метод базового класса переопределяется в производном классе, используется версия в производном классе, даже если вызывающий код не "знал", что объект является экземпляром производного класса. Например:
public class Base { public virtual void SomeMethod() { } } public class Derived : Base { public override void SomeMethod() { } } ... Base d = new Derived(); d.SomeMethod();в конечном итоге вызов производного.SomeMethod, если это переопределяет базу.Метода someMethod.
теперь, если вы используйте новая ключевое слово вместо переопределить метод в производном классе не переопределить метод в базовом классе, он просто скрывает это. В этом случае код выглядит так:
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();сначала позвонить.Какой-то другой метод , потом производный.SomeOtherMethod . Это фактически два совершенно разных метода, которые имеют одно и то же имя, а не производный метод, переопределяющий базовый метод.
Если вы не укажете ни new, ни переопределяет, результирующий вывод такой же, как если бы вы указали new, но вы также получите предупреждение компилятора (поскольку вы можете не знать, что вы скрываете метод в методе базового класса, или действительно Вы, возможно, хотели его переопределить и просто забыли включить ключевое слово).
переопределяющее объявление свойства может включать загерметизированная модификатор. Использование этого модификатора предотвращает дальнейшее переопределение свойства производным классом. Доступ в запечатанном собственность также опечатаны.
любой метод может быть переопределяемым (=
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");когда невиртуальный метод
GetPersonTypeназываетсяFiendэкземпляра это на самом делеPerson.GetPersonTypeэто звонил:Console.WriteLine(friend.GetPersonType()); // "person"когда виртуальный метод
GetNameназываетсяFriendпримерFriend.GetNameэто называется:Console.WriteLine(friend.GetName()); // "Onotole"когда виртуальный метод
GetNameназываетсяPersonпримерPerson.GetNameэто называется:Console.WriteLine(person.GetName()); // "generic name"когда вызывается невиртуальный метод, тело метода не просматривается-компилятор уже знает фактический метод, который должен быть вызван. В то время как с виртуальными методами компилятор не может быть уверен, какой из них вызвать, и это посмотрел вверх во время выполнения в иерархии классов снизу вверх, начиная с типа экземпляра, на который вызывается метод: for
friend.GetNameэто выглядит, начиная сFriendкласс и находит его сразу, заperson.GetNameкласс начинается сPersonи находит его там.иногда вы делаете подкласс, переопределяете виртуальный метод, и вы не хотите больше переопределений в иерархии-вы используете
sealed overrideдля этого (говоря, что вы последний, кто переопределяет метод):class Mike : Friend { public sealed override String GetName() { return "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' s-вы звонитеMike.GetName. Здесь не выполняется поиск во время выполнения, поскольку оба метода не являются виртуальными.вы всегда можете создать
newметоды - независимо от того, являются ли методы, которые вы скрываете, виртуальными или нет.это также относится к свойствам и событиям - они представлены в виде методов внизу.
по умолчанию метод не может быть переопределен в производном классе, если он объявлен
virtualилиabstract.virtualозначает проверять наличие новых реализаций перед вызовом иabstractозначает то же самое, но он гарантированно будет переопределен во всех производных классах. Кроме того, реализация не требуется в базовом классе, потому что она будет переопределена в другом месте.исключением из вышесказанного является
newмодификатор. Метод не объявленvirtualилиabstractможно переопределить с помощьюnewмодификатор в производном классе. При вызове метода в базовом классе выполняется базовый метод, а при вызове в производном классе выполняется новый метод. Все этоnewключевые слова позволяет сделать это двумя способами:С тем же именем в иерархии классов.наконец-то a
sealedмодификатор разрывает цепиvirtualметоды и делает их не переопределяемый снова. Это используется не часто, но вариант быть там. Это имеет больше смысла с цепочкой из 3 классов, каждый из которых происходит от предыдущегоA -> B -> Cесли
Aестьvirtualилиabstractметод, то естьoverriddenнаB, то он также может предотвратитьCот изменения его снова, объявив егоsealedinB.
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 DBase b = new Derived();
- используя
 virtualв базовом классе и переопределить вDerivedдаст D (полиморфизм).- используя
 overrideбезvirtualнаBaseвыдаст ошибку.- аналогично писать метод (без переопределения) с
 virtualбудет писать ' B ' с предупреждением (потому что полиморфизм не делается).- чтобы скрыть такое предупреждение, как в выше точки пишите
 newперед этим простой метод вDerived.newключевое слово-это другая история, оно просто скрывает предупреждение, которое говорит, что свойство с тем же именем находится в базовом классе.
virtualилиnewоба одинаковы, за исключением новый модификатор
newиoverrideнельзя использовать перед тем же методом или свойством.sealedперед любым классом или методом заблокировать его использоваться в производном классе, и это дает ошибку времени компиляции.