В чем разница между абстрактным методом и виртуальным методом? В каких случаях рекомендуется использовать абстрактные или виртуальные методы? Какой из них лучший?
В чем разница между абстрактным методом и виртуальным методом?
Ответы (28)
Абстрактная функция не может иметь функциональных возможностей. По сути, вы говорите, что любой дочерний класс ДОЛЖЕН предоставлять свою собственную версию этого метода, однако она слишком общая, чтобы даже пытаться реализовать в родительском классе.
Виртуальная функция, по сути, говорит: смотрите, вот функциональность, которая может быть или не быть достаточно хорошей для дочернего класса. Так что, если он достаточно хорош, используйте этот метод, если нет, то переопределите меня и предоставьте свои собственные функции.
Абстрактная функция не имеет реализации и может быть объявлена только в абстрактном классе. Это заставляет производный класс предоставить реализацию.
Виртуальная функция предоставляет реализацию по умолчанию и может существовать как в абстрактном, так и в не абстрактном классе.
Так например:
public abstract class myBase
{
//If you derive from this class you must implement this method. notice we have no method body here either
public abstract void YouMustImplement();
//If you derive from this class you can change the behavior but are not required to
public virtual void YouCanOverride()
{
}
}
public class MyBase
{
//This will not compile because you cannot have an abstract method in a non-abstract class
public abstract void YouMustImplement();
}
MyBase
класс не должен каким-то образом реализовывать класс abstract? Я делаю это не часто, поэтому могу ошибаться. Я не вижу этого в вашем примере.
- person jp2code; 27.06.2014
- Только
abstract
классы могут иметьabstract
членов. - Класс, не являющийся
abstract
, который наследуется отabstract
класса, долженoverride
егоabstract
члены. - Член
abstract
неявно означаетvirtual
. - Член
abstract
не может предоставить какую-либо реализацию (abstract
в некоторых языках называетсяpure virtual
).
virtual
или не virtual
. Член abstract
(т.е. абстрактное свойство, абстрактный метод) подобен виртуальному методу, то есть вы можете переопределить его, за исключением того, что он не несет в себе реализацию по умолчанию.
- person mmx; 15.01.2014
Вы всегда должны переопределять абстрактную функцию.
Таким образом:
- Абстрактные функции - когда наследник должен предоставить свою собственную реализацию
- Виртуальный - когда решение остается за наследником
Абстрактная функция:
- Его можно объявить только внутри абстрактного класса.
- Он содержит только объявление метода, а не реализацию в абстрактном классе.
- Его необходимо переопределить в производном классе.
Виртуальная функция:
- Он может быть объявлен как внутри абстрактного, так и не абстрактного класса.
- Он содержит реализацию метода.
- Это может быть отменено.
пояснение: с аналогиями. надеюсь, это поможет вам.
Контекст
Работаю на 21 этаже дома. И я параноик по поводу огня. Время от времени где-то в мире огонь сжигает небоскреб. Но, к счастью, где-то здесь есть инструкция о том, что делать в случае пожара:
FireEscape ()
- Не собирайте вещи
- Пройдите к пожарной лестнице
- Выйти из здания
По сути, это виртуальный метод под названием FireEscape ().
Виртуальный метод
Этот план хорош для 99% случаев. Это базовый план, который работает. Но есть 1% шанс, что пожарная лестница заблокирована или повреждена, и в этом случае вы полностью облажались, и вы превратитесь в тост, если не предпримете решительных действий. С виртуальными методами вы можете сделать именно это: вы можете заменить базовый план FireEscape () своей собственной версией плана:
- Бежать к окну
- Выпрыгнуть в окно
- Парашют безопасно опускается на дно
Другими словами, виртуальные методы предоставляют базовый план, который при необходимости можно изменить. Подклассы могут переопределить виртуальный метод родительского класса, если программист сочтет это целесообразным.
Абстрактные методы
Не все организации хорошо подготовлены. Некоторые организации не проводят пожарных учений. У них нет общей политики побега. Каждый сам за себя. Менеджмент заинтересован только в том, чтобы такая политика существовала.
Другими словами, каждый человек вынужден разработать свой собственный метод FireEscape (). Один парень выйдет по пожарной лестнице. Другой парень спрыгнет с парашютом. Другой парень будет использовать ракетные двигатели, чтобы улететь от здания. Другой парень спустится на канатной дороге. Руководству все равно, как вы сбежите, пока у вас есть базовый план FireEscape () - в противном случае вы можете быть уверены, что OHS обрушится на организацию, как тонна кирпичей. Вот что подразумевается под абстрактным методом.
В чем снова разница между ними?
Абстрактный метод: подклассы принудительно реализуют собственный метод FireEscape. С виртуальным методом у вас есть базовый план, ожидающий вас, но вы можете выбрать реализовать свой собственный, если он недостаточно хорош.
Теперь это было не так уж сложно, правда?
Абстрактный метод: когда класс содержит абстрактный метод, этот класс должен быть объявлен как абстрактный. Абстрактный метод не имеет реализации, и поэтому классы, производные от этого абстрактного класса, должны предоставлять реализацию для этого абстрактного метода.
Виртуальный метод: класс может иметь виртуальный метод. У виртуального метода есть реализация. При наследовании от класса, имеющего виртуальный метод, вы можете переопределить виртуальный метод и предоставить дополнительную логику или заменить логику своей собственной реализацией.
Когда что использовать: в некоторых случаях вы знаете, что определенные типы должны иметь определенный метод, но вы не знаете, какую реализацию должен иметь этот метод.
В таких случаях вы можете создать интерфейс, содержащий метод с этой подписью. Однако, если у вас есть такой случай, но вы знаете, что у разработчиков этого интерфейса также будет другой общий метод (для которого вы уже можете предоставить реализацию), вы можете создать абстрактный класс. Затем этот абстрактный класс содержит абстрактный метод (который должен быть переопределен) и другой метод, содержащий «общую» логику.
Виртуальный метод следует использовать, если у вас есть класс, который можно использовать напрямую, но для которого вы хотите, чтобы наследники могли изменять определенное поведение, хотя это не обязательно.
Абстрактный метод - это метод, который необходимо реализовать для создания конкретного класса. Объявление находится в абстрактном классе (и любой класс с абстрактным методом должен быть абстрактным классом), и он должен быть реализован в конкретном классе.
Виртуальный метод - это метод, который можно переопределить в производном классе, используя переопределение, заменяющее поведение в суперклассе. Если вы не переопределите, вы получите исходное поведение. Если вы это сделаете, вы всегда будете вести себя по-новому. Это в отличие от не виртуальных методов, которые не могут быть переопределены, но могут скрыть исходный метод. Это делается с помощью модификатора new
.
См. Следующий пример:
public class BaseClass
{
public void SayHello()
{
Console.WriteLine("Hello");
}
public virtual void SayGoodbye()
{
Console.WriteLine("Goodbye");
}
public void HelloGoodbye()
{
this.SayHello();
this.SayGoodbye();
}
}
public class DerivedClass : BaseClass
{
public new void SayHello()
{
Console.WriteLine("Hi There");
}
public override void SayGoodbye()
{
Console.WriteLine("See you later");
}
}
Когда я создаю экземпляр DerivedClass
и звоню SayHello
или SayGoodbye
, я получаю «Привет!» И «Увидимся позже». Если я звоню HelloGoodbye
, я получаю «Привет» и «Увидимся позже». Это потому, что SayGoodbye
является виртуальным и может быть заменен производными классами. SayHello
только скрыт, поэтому, когда я вызываю его из своего базового класса, я получаю свой исходный метод.
Абстрактные методы неявно виртуальны. Они определяют поведение, которое должно присутствовать, больше похоже на интерфейс.
Абстрактные методы всегда виртуальны. У них не может быть реализации.
В этом главное отличие.
По сути, вы должны использовать виртуальный метод, если у вас есть его реализация «по умолчанию» и вы хотите разрешить потомкам изменять его поведение.
С помощью абстрактного метода вы заставляете потомков предоставлять реализацию.
Я упростил это, внося некоторые улучшения в следующие классы (из других ответов):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestOO
{
class Program
{
static void Main(string[] args)
{
BaseClass _base = new BaseClass();
Console.WriteLine("Calling virtual method directly");
_base.SayHello();
Console.WriteLine("Calling single method directly");
_base.SayGoodbye();
DerivedClass _derived = new DerivedClass();
Console.WriteLine("Calling new method from derived class");
_derived.SayHello();
Console.WriteLine("Calling overrided method from derived class");
_derived.SayGoodbye();
DerivedClass2 _derived2 = new DerivedClass2();
Console.WriteLine("Calling new method from derived2 class");
_derived2.SayHello();
Console.WriteLine("Calling overrided method from derived2 class");
_derived2.SayGoodbye();
Console.ReadLine();
}
}
public class BaseClass
{
public void SayHello()
{
Console.WriteLine("Hello\n");
}
public virtual void SayGoodbye()
{
Console.WriteLine("Goodbye\n");
}
public void HelloGoodbye()
{
this.SayHello();
this.SayGoodbye();
}
}
public abstract class AbstractClass
{
public void SayHello()
{
Console.WriteLine("Hello\n");
}
//public virtual void SayGoodbye()
//{
// Console.WriteLine("Goodbye\n");
//}
public abstract void SayGoodbye();
}
public class DerivedClass : BaseClass
{
public new void SayHello()
{
Console.WriteLine("Hi There");
}
public override void SayGoodbye()
{
Console.WriteLine("See you later");
}
}
public class DerivedClass2 : AbstractClass
{
public new void SayHello()
{
Console.WriteLine("Hi There");
}
// We should use the override keyword with abstract types
//public new void SayGoodbye()
//{
// Console.WriteLine("See you later2");
//}
public override void SayGoodbye()
{
Console.WriteLine("See you later");
}
}
}
Привязка - это процесс сопоставления имени с единицей кода.
Поздняя привязка означает, что мы используем имя, но откладываем сопоставление. Другими словами, мы сначала создаем / упоминаем имя и позволяем некоторому последующему процессу обрабатывать отображение кода на это имя.
Теперь рассмотрим:
- По сравнению с людьми машины действительно хороши в поиске и сортировке.
- По сравнению с машинами люди действительно хороши в изобретениях и инновациях.
Итак, краткий ответ: virtual
- это инструкция позднего связывания для машины (среда выполнения), тогда как abstract
- инструкция позднего связывания для человека (программиста).
Другими словами, virtual
означает:
«Уважаемая среда выполнения, привяжите соответствующий код к этому имени, делая то, что у вас получается лучше всего: поиск»
Принимая во внимание, что abstract
означает:
«Уважаемый программист, привяжите соответствующий код к этому имени, делая то, что у вас получается лучше всего: изобретать»
Для полноты картины перегрузка означает:
«Уважаемый компилятор, привяжите соответствующий код к этому имени, выполнив то, что у вас лучше всего получается: сортировка».
Вы в основном используете виртуальный метод, когда хотите, чтобы наследники расширили функциональность, ЕСЛИ они захотят.
Вы используете абстрактные методы, когда хотите, чтобы наследники реализовали функциональность (и в этом случае у них нет выбора)
Виртуальный метод:
Виртуальный означает, что мы МОЖЕМ переопределить его.
Виртуальная функция имеет реализацию. Когда мы наследуем класс, мы можем переопределить виртуальную функцию и предоставить нашу собственную логику.
- Мы можем изменить тип возвращаемого значения виртуальной функции при реализации функции
в дочернем классе (что можно назвать концепцией затенения).
Абстрактный метод
Абстракция означает, что мы ДОЛЖНЫ ее переопределить.
Абстрактная функция не имеет реализации и должна находиться в абстрактном классе.
Это можно только декларировать. Это заставляет производный класс предоставить его реализацию.
Абстрактный член неявно виртуален. Реферат можно назвать чисто виртуальным на некоторых языках.
public abstract class BaseClass { protected abstract void xAbstractMethod(); public virtual void xVirtualMethod() { var x = 3 + 4; } }
Я видел в некоторых местах, что абстрактный метод определяется следующим образом. **
«Абстрактный метод должен быть реализован в дочернем классе»
** Я чувствовал, что это нравится.
Необязательно, чтобы абстрактный метод был реализован в дочернем классе, если дочерний класс также является абстрактным ..
1) Абстрактный метод не может быть частным методом. 2) Абстрактный метод не может быть реализован в том же абстрактном классе.
Я бы сказал ... если мы реализуем абстрактный класс, вы должны переопределить абстрактные методы из базового абстрактного класса. Потому что .. Реализация абстрактного метода осуществляется с помощью ключевого слова override. Аналогично виртуальному методу.
Необязательно, чтобы виртуальный метод был реализован в унаследованном классе.
----------CODE--------------
public abstract class BaseClass
{
public int MyProperty { get; set; }
protected abstract void MyAbstractMethod();
public virtual void MyVirtualMethod()
{
var x = 3 + 4;
}
}
public abstract class myClassA : BaseClass
{
public int MyProperty { get; set; }
//not necessary to implement an abstract method if the child class is also abstract.
protected override void MyAbstractMethod()
{
throw new NotImplementedException();
}
}
public class myClassB : BaseClass
{
public int MyProperty { get; set; }
//You must have to implement the abstract method since this class is not an abstract class.
protected override void MyAbstractMethod()
{
throw new NotImplementedException();
}
}
В большинстве приведенных выше примеров используется код - и они очень хороши. Мне не нужно добавлять к тому, что они говорят, но ниже приводится простое объяснение, в котором используются аналогии, а не код / технические термины.
Простое объяснение - объяснение с использованием аналогий
Абстрактный метод
Вспомните Джорджа Буша. Он говорит своим солдатам: «Идите в бой в Ираке». Вот и все. Все, что он указал, - это необходимость борьбы. Он не уточняет, как именно это произойдет. Но я имею в виду, вы не можете просто выйти и «драться»: что именно это означает? мне драться на B-52 или на моем дерринжере? Эти конкретные детали оставлены кому-то другому. Это абстрактный метод.
Виртуальный метод
Дэвид Петреус высокопоставлен в армии. Он определил, что означает бой:
- Найдите врага
- Нейтрализуйте его.
- Выпей пива после
Проблема в том, что это очень общий метод. Это хороший метод, который работает, но иногда недостаточно конкретен. Для Петреуса хорошо то, что у его приказов есть свобода действий и размах - он позволил другим изменить свое определение «борьбы» в соответствии с их особыми требованиями.
Private Job Bloggs читает приказ Петреуса и получает разрешение на реализацию его собственной версии боя в соответствии с его особыми требованиями:
- Найди врага.
- Выстрелите ему в голову.
- Иди домой
- Выпей пива.
Нури аль-Малики также получает такие же приказы от Петреуса. Он тоже должен сражаться. Но он политик, а не пехотинец. Очевидно, он не может стрелять в головы своим политическим врагам. Поскольку Петреус дал ему виртуальный метод, Малики может реализовать свою собственную версию метода боя в соответствии с его конкретными обстоятельствами:
- Найди врага.
- Его арестуют по сфабрикованным обвинениям.
- Иди домой
- Выпей пива.
Другими словами, виртуальный метод предоставляет стандартные инструкции - но это общие инструкции, которые могут быть конкретизированы людьми в армейской иерархии в соответствии с их конкретными обстоятельствами.
Разница между ними
Джордж Буш не доказывает подробностей реализации. Это должно быть предоставлено кем-то другим. Это абстрактный метод.
Петреус, с другой стороны, действительно предоставляет детали реализации, но он разрешил своим подчиненным переопределить его приказы своей собственной версией, если они смогут придумать что-нибудь получше.
надеюсь, это поможет.
Абстрактная функция (метод):
● Абстрактный метод - это метод, объявленный с ключевым словом abstract.
● У него нет тела.
● Он должен быть реализован производным классом.
● Если метод является абстрактным, класс должен абстрагироваться.
виртуальная функция (метод):
● Виртуальный метод - это метод, который объявлен с ключевым словом virtual и может быть переопределен методом производного класса с помощью ключевого слова override.
● Производный класс решает, переопределять его или нет.
Ответ давался несколько раз, но вопрос о том, когда использовать каждый из них, принимается во время разработки. Я бы счел хорошей практикой попытаться объединить определения общих методов в отдельные интерфейсы и вывести их в классы на соответствующих уровнях абстракции. Выгрузка общего набора определений абстрактных и виртуальных методов в класс делает класс unistantiable, когда может быть лучше всего определить неабстрактный класс, который реализует набор кратких интерфейсов. Как всегда, это зависит от того, что лучше всего соответствует потребностям вашего приложения.
Абстрактная функция не может иметь тела и ДОЛЖНА быть переопределена дочерними классами.
Виртуальная функция будет иметь тело и может или не может быть переопределена дочерними классами.
С общего объектно-ориентированного представления:
Относительно абстрактного метода: когда вы помещаете абстрактный метод в родительский класс, на самом деле вы говорите дочерним классам: Эй, обратите внимание, что у вас есть подпись метода, подобная этой. И если вы хотите использовать его, вы должны реализовать свой собственный!
Что касается виртуальной функции: когда вы помещаете виртуальный метод в родительский класс, вы говорите производным классам: «Эй, здесь есть функция, которая что-то делает за вас. Если это полезно для вас, просто используйте его. Если нет, переопределите это и реализуйте свой код, даже если вы можете использовать мою реализацию в своем коде!
это некоторая философия о различии между этими двумя концепциями в общем OO
Абстрактная функция - это «просто» подпись без реализации. Он используется в интерфейсе, чтобы объявить, как можно использовать класс. Он должен быть реализован в одном из производных классов.
Виртуальная функция (фактически метод) - это функция, которую вы также объявляете, и она должна быть реализована в одном из классов иерархии наследования.
Унаследованные экземпляры такого класса также наследуют реализацию, если вы ее не реализуете, в классе более низкой иерархии.
Если класс является производным от этого абстрактного класса, он вынужден переопределить абстрактный член. Это отличается от виртуального модификатора, который указывает, что член может быть переопределен.
В C # нет ничего вызывающего виртуальный класс.
Для функций
- Абстрактная функция имеет только сигнатуру, класс диска должен иметь приоритет над функциональностью.
- Виртуальная функция будет содержать часть функциональности, которую класс привода может или не может переопределить в соответствии с требованиями.
Вы можете решить с вашим требованием.
У абстрактного метода нет реализации, он объявлен в родительском классе. Дочерний класс отвечает за реализацию этого метода.
Виртуальный метод должен иметь реализацию в родительском классе, и это помогает дочернему классу сделать выбор, использовать ли эту реализацию родительского класса или иметь новую реализацию для этого метода в дочернем классе.
Исходя из фона C ++, виртуальный C # соответствует виртуальному C ++, а абстрактные методы C # соответствуют чистой виртуальной функции C ++.
Абстрактная функция или метод - это общедоступное "имя операции", предоставляемое классом, ее цель, наряду с абстрактными классами, в первую очередь - обеспечить форму ограничения в дизайне объектов по отношению к структуре, которую объект должен осуществлять.
Фактически классы, которые наследуются от его абстрактного класса, должны предоставлять реализацию этому методу, обычно компиляторы вызывают ошибки, когда они этого не делают.
Использование абстрактных классов и методов важно в основном для того, чтобы избежать того, что, сосредоточив внимание на деталях реализации при разработке классов, структура классов будет слишком связана с реализациями, таким образом создавая зависимости и связь между классами, которые взаимодействуют между собой.
Виртуальная функция или метод - это просто метод, моделирующий общедоступное поведение класса, но мы можем оставить его свободным для изменения в цепочке наследования, поскольку мы думаем, что дочерним классам может потребоваться реализовать некоторые специальные расширения для этого поведения.
Оба они представляют собой форму полиморфизма в парадигме объектной ориентации.
Мы можем использовать абстрактные методы и виртуальные функции вместе, чтобы поддерживать хорошую модель наследования.
Мы проектируем хорошую абстрактную структуру основных объектов нашего решения, затем создаем базовые реализации, определяя те, которые более склонны к дальнейшей специализации, и делаем их виртуальными, наконец, мы специализируем наши базовые реализации, в конечном итоге «отменяя» унаследованные виртуальные.
Здесь я пишу пример кода, надеясь, что это может быть довольно ощутимый пример, позволяющий увидеть поведение интерфейсов, абстрактных классов и обычных классов на самом базовом уровне. Вы также можете найти этот код в github как проект, если хотите использовать его в качестве демонстрации: https://github.com/usavas/JavaAbstractAndInterfaceDemo
public interface ExampleInterface {
// public void MethodBodyInInterfaceNotPossible(){
// }
void MethodInInterface();
}
public abstract class AbstractClass {
public abstract void AbstractMethod();
// public abstract void AbstractMethodWithBodyNotPossible(){
//
// };
//Standard Method CAN be declared in AbstractClass
public void StandardMethod(){
System.out.println("Standard Method in AbstractClass (super) runs");
}
}
public class ConcreteClass
extends AbstractClass
implements ExampleInterface{
//Abstract Method HAS TO be IMPLEMENTED in child class. Implemented by ConcreteClass
@Override
public void AbstractMethod() {
System.out.println("AbstractMethod overridden runs");
}
//Standard Method CAN be OVERRIDDEN.
@Override
public void StandardMethod() {
super.StandardMethod();
System.out.println("StandardMethod overridden in ConcreteClass runs");
}
public void ConcreteMethod(){
System.out.println("Concrete method runs");
}
//A method in interface HAS TO be IMPLEMENTED in implementer class.
@Override
public void MethodInInterface() {
System.out.println("MethodInInterface Implemented by ConcreteClass runs");
// Cannot declare abstract method in a concrete class
// public abstract void AbstractMethodDeclarationInConcreteClassNotPossible(){
//
// }
}
}
Методы можно разделить в зависимости от обязательности / их отсутствия и разрешения / их отмены:
- абстрактный (чистый) / конкретный (нечистый): должен быть изменен / не может быть изменен;
- виртуальный / реальный: можно переопределить / нельзя переопределить.
Итак, по определению абстрактные методы могут быть только виртуальными, а реальные методы могут быть только конкретными.
Насколько я понимаю:
Абстрактные методы:
Только абстрактный класс может содержать абстрактные методы. Также производный класс должен реализовать метод, и в классе не предусмотрено никакой реализации.
Виртуальные методы:
Класс может объявлять их, а также обеспечивать их реализацию. Также производный класс должен реализовать метод, чтобы переопределить его.