В чем разница между абстрактной функцией и виртуальной функцией?

1435

В чем разница между абстрактной функцией и виртуальной функцией? В каких случаях рекомендуется использовать виртуальный или абстрактный? Какой из них лучший?

  • 248
    Абстрактная функция должна быть переопределена, в то время как виртуальная функция может быть переопределена.
  • 15
    Виртуальные функции могут иметь стандартную / стандартную реализацию в базовом классе.
Показать ещё 1 комментарий
Теги:
oop
programming-languages
abstract
virtual-functions
virtual

26 ответов

2371
Лучший ответ

Абстрактная функция не может иметь функциональность.. Вы в основном говорите, что любой дочерний класс ДОЛЖЕН дать собственную версию этого метода, однако он слишком общий, чтобы даже попытаться реализовать в родительском классе.

Виртуальная функция, в основном говорит о взгляде, здесь функции, которые могут или не могут быть достаточно хорошими для дочернего класса. Поэтому, если это достаточно хорошо, используйте этот метод, если нет, то переопределите меня и предоставите свои собственные функции.

  • 361
    И, конечно, если вы переопределяете виртуальный метод, вы всегда можете обратиться к родительскому методу, вызвав base.Foo (...)
  • 188
    Благодарю. Это гораздо лучшее и более простое объяснение, чем что-либо в документации MSDN. (У меня была головная боль после пяти минут чтения этого: msdn.microsoft.com/en-us/library/aa645767(v=vs.71).aspx )
Показать ещё 11 комментариев
283

Абстрактная функция не имеет реализации и может быть объявлена ​​только в абстрактном классе. Это заставляет производный класс обеспечивать реализацию. Виртуальная функция предоставляет реализацию по умолчанию и может существовать либо в абстрактном классе, либо в неабстрактном классе. Так, например:

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();
}
  • 24
    Очень полезно увидеть пример кода - помогает сделать более понятными различные объяснения в ответах.
  • 2
    Я откатил ответ до предыдущей версии: два класса являются просто примерами, первый класс скомпилируется, поскольку он помечен как абстрактный, второй - нет. Независимо от того, наследует ли MyBase какой-то другой класс или нет, не имеет значения.
Показать ещё 2 комментария
78
  • Только классы abstract могут иметь abstract членов.
  • Класс non abstract, который наследует от класса abstract должен override его abstract членов.
  • Член abstract неявно virtual.
  • Член abstract не может предоставить какую-либо реализацию (abstract называется pure virtual на некоторых языках).
  • 0
    Номер 3 не имеет смысла для меня. Я думаю, что вы хотели сказать «член абстрактного класса неявно виртуален» (т. Е. Вы можете предоставить ему функциональность, не указывая, что он виртуальный).
  • 5
    Нет, я имел в виду именно то, что написал. Член абстрактного класса может быть virtual или не virtual . abstract член (то есть абстрактное свойство, абстрактный метод) похож на виртуальный метод, то есть вы можете переопределить его, за исключением того, что он не несет с собой реализацию по умолчанию.
Показать ещё 2 комментария
58

Вы всегда должны переопределять абстрактную функцию.

Таким образом:

  • Абстрактные функции - при наследник должен предоставить свою собственную реализацию
  • Виртуальный - когда , до наследователя решать
34

Абстрактная функция:

  • Он может быть объявлен только внутри абстрактного класса.
  • Он содержит только Объявление метода не реализация в абстрактном классе.
  • Он должен быть переопределен в производном классе.

Виртуальная функция:

  • Он может быть объявлен как внутри абстрактного, так и не абстрактного класса.
  • Он содержит реализацию метода.
  • Это может быть отменено.
28

Абстрактный метод: Когда класс содержит абстрактный метод, этот класс должен быть объявлен как абстрактный. Абстрактный метод не имеет реализации и, следовательно, классы, которые вытекают из этого абстрактного класса, должны обеспечивать реализацию этого абстрактного метода.

Виртуальный метод: Класс может иметь виртуальный метод. Виртуальный метод имеет реализацию. Когда вы наследуете класс, который имеет виртуальный метод, вы можете переопределить виртуальный метод и предоставить дополнительную логику или заменить логику своей собственной реализацией.

Когда использовать что: В некоторых случаях вы знаете, что определенные типы должны иметь определенный метод, но вы не знаете, какую реализацию должен иметь этот метод.
В таких случаях вы можете создать интерфейс, содержащий метод с этой сигнатурой. Однако, если у вас есть такой случай, но вы знаете, что разработчики этого интерфейса также будут иметь еще один распространенный метод (для которого вы уже можете обеспечить реализацию), вы можете создать абстрактный класс. Этот абстрактный класс затем содержит абстрактный метод (который должен быть переопределен) и другой метод, который содержит "общую" логику.

Виртуальный метод следует использовать, если у вас есть класс, который можно использовать напрямую, но для которого вы хотите, чтобы наследователи могли изменять определенное поведение, хотя это необязательно.

24

объяснение: с аналогиями. надеюсь, это поможет вам.

Контекст

Я работаю на 21-м этаже здания. И я параноик о пожаре. Время от времени, где-то в мире, огонь сжигает небоскреб. Но, к счастью, у нас есть инструкция по работе где-то здесь, что делать в случае пожара:

FireEscape()

  • Не собирайте вещи
  • Прогулка к пожарной лестнице.
  • Выход из строя

Это виртуальный метод, называемый FireEscape()

Виртуальный метод

Этот план довольно хорош для 99% обстоятельств. Это основной план, который работает. Но есть 1% -ый шанс того, что пожарный выход заблокирован или поврежден, и в этом случае вы полностью завинчены, и вы станете тостом, если не предпримете какие-то решительные действия. С помощью виртуальных методов вы можете сделать именно это: вы можете переопределить базовый план FireEscape() своей собственной версией плана:

  • Запустить в окно
  • Выйдите из окна
  • Парашют безопасно снизу

Другими словами, виртуальные методы обеспечивают базовый план, который может быть переоценен, если вам нужно. Подклассы могут переопределять виртуальный метод родительского класса, если программист считает это подходящим.

Абстрактные методы

Не все организации хорошо просверлены. Некоторые организации не выполняют противопожарные упражнения. У них нет общей политики побега. Каждый человек для себя. Менеджмент заинтересован только в такой существующей политике.

Другими словами, каждый человек вынужден разработать собственный метод FireEscape(). Один парень выйдет из пожарной лестницы. Другой парень будет парашютом. Другой парень будет использовать ракетные двигательные технологии, чтобы улететь из здания. Другой парень исчезнет. Менеджменту все равно, как вы избегаете, если у вас есть базовый план FireEscape(), если они не могут быть гарантированы. OHS придет к организации, как тонна кирпичей. Это то, что подразумевается под абстрактным методом.

Какая разница между двумя?

Абстрактный метод: подклассы принудительно выполняют собственный метод FireEscape. С помощью виртуального метода у вас есть базовый план, ожидающий вас, но вы можете реализовать его, если он недостаточно хорош.

Теперь это было не так сложно?

22

Абстрактный метод - это метод, который должен быть реализован для создания конкретного класса. Объявление находится в абстрактном классе (и любой класс с абстрактным методом должен быть абстрактным классом), и он должен быть реализован в конкретном классе.

Виртуальный метод - это метод, который может быть переопределен в производном классе с использованием переопределения, заменяя поведение в суперклассе. Если вы не переопределите, вы получите оригинальное поведение. Если вы это сделаете, вы всегда получите новое поведение. Это противоречит не виртуальным методам, которые нельзя переопределить, но могут скрыть исходный метод. Это делается с помощью модификатора 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 скрыто, поэтому, когда я вызываю это из моего базового класса, я получаю свой оригинальный метод.

Абстрактные методы неявно виртуальны. Они определяют поведение, которое должно присутствовать, больше похоже на интерфейс.

10

Я сделал это проще, сделав некоторые улучшения в следующих классах (из других ответов):

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");
        }
    }
}
10

Абстрактные методы всегда являются виртуальными. У них не может быть реализации.

Это основное отличие.

В принципе, вы бы использовали виртуальный метод, если у вас есть реализация по умолчанию, и вы хотите, чтобы потомки меняли свое поведение.

С помощью абстрактного метода вы вынуждаете потомков предоставлять реализацию.

5

Привязка - это процесс отображения имени на единицу кода.

Позднее связывание означает, что мы используем имя, но откладываем отображение. Другими словами, мы сначала создаем/упоминаем имя и позволяем некоторому последующему процессу обрабатывать сопоставление кода с этим именем.

Теперь рассмотрим:

  • По сравнению с людьми машины действительно хороши в поиске и сортировке
  • По сравнению с машинами люди действительно хороши в изобретательстве и инновациях

Итак, краткий ответ: virtual - это команда позднего связывания для машины (время выполнения), тогда как abstract - инструкция позднего связывания для человека (программиста)

Другими словами, virtual означает:

"Дорогая среда выполнения, свяжите соответствующий код с этим именем, выполняя то, что вы делаете лучше всего: поиск"

В то время как abstract означает:

"Уважаемый программист, пожалуйста, свяжите соответствующий код с этим именем, выполняя то, что вы делаете лучше всего: изобретая"

Для полноты, перегрузка означает:

Msgstr "Уважаемый компилятор, свяжите соответствующий код с этим именем, выполняя то, что вы делаете лучше всего: сортировку".

3

Виртуальный метод:

  • Виртуальный означает, что мы можем переопределить его.

  • Виртуальная функция имеет реализацию. Когда мы наследуем класс, мы можем переопределить виртуальную функцию и предоставить нашу собственную логику.

  • Мы можем изменить тип возвращаемого значения Виртуальной функции при реализации
    функция в дочернем классе (что можно сказать как понятие
    Затенение).

Абстрактный метод

  • Абстрактное означает, что мы ДОЛЖНЫ переопределить его.

  • Абстрактная функция не имеет реализации и должна быть в абстрактном классе.

  • Это можно только объявить. Это заставляет производный класс обеспечить его реализацию.

  • Абстрактный член неявно виртуален. Аннотация может называться чисто виртуальной в некоторых языках.

    public abstract class BaseClass
    { 
        protected abstract void xAbstractMethod();
    
        public virtual void xVirtualMethod()
        {
            var x = 3 + 4;
        }
    } 
    
3

Я видел в некоторых местах абстрактный метод, как показано ниже. **

"Абстрактному методу необходимо реализовать в дочернем классе

** Я чувствовал, что это похоже.

Нет необходимости, чтобы абстрактный метод был реализован в дочернем классе, , если дочерний класс также является абстрактным.

1) Абстрактный метод не может быть приватным методом. 2) Абстрактный метод cant будет реализован в том же абстрактном классе.

Я бы сказал, что если мы реализуем абстрактный класс, вам придется переопределить абстрактные методы из базового абстрактного класса. Потому что.. Реализация абстрактного метода с ключевым словом переопределить. Подобно виртуальному методу.

Не обязательно, чтобы виртуальный метод был реализован в унаследованном классе.

                                 ----------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();
    }
}
3

В основном вы используете виртуальный метод, когда хотите, чтобы наследники расширяли функциональность, если они хотят.

Вы используете абстрактные методы, когда хотите, чтобы наследователи реализовали функциональность (и в этом случае у них нет выбора)

2

Абстрактная функция (метод):

● Абстрактный метод - это метод, который объявлен с ключевым словом abstract.

● У него нет тела.

● Это должно быть реализовано производным классом.

● Если метод абстрактный, то класс должен абстрактный.

виртуальная функция (метод):

● Виртуальный метод - это метод, который объявлен с ключевым словом virtual, и его можно переопределить методом производного класса с помощью ключевого слова override.

● Это до производного класса, переопределить это или нет.

2

В большинстве приведенных выше примеров используется код - и они очень хороши. Мне не нужно добавлять к тому, что они говорят, но следующее простое объяснение, которое использует аналогии, а не код/​​технические термины.

Простое объяснение - Объяснение с использованием аналогов

Абстрактный метод

Подумайте, Джордж Буш. Он говорит своим солдатам: "Иди бой в Ираке". И это так. Все, что он указал, - это то, что нужно сражаться. Он не уточняет, как именно это произойдет. Но я имею в виду, вы не можете просто выйти и "драться": что это значит? я сражаюсь с B-52 или моим derringer? Эти конкретные детали оставлены кому-то еще. Это абстрактный метод.

Виртуальный метод

Дэвид Петреус высоко в армии. Он определил, что означает борьба:

  • Найдите врага
  • Нейтрализовать его.
  • После этого пиво

Проблема в том, что это очень общий метод. Это хороший метод, который работает, но иногда не является достаточно конкретным. Хорошая вещь для Петреуса заключается в том, что его приказы имеют свободу действий и возможности - он позволил другим изменить свое определение "битвы" в соответствии с их конкретными требованиями.

Частная работа Bloggs читает заказ Петреуса и получает разрешение на реализацию своей собственной версии боя в соответствии с его особыми требованиями:

  • Найдите врага.
  • Стреляйте в голову.
  • Перейти на главную страницу
  • Пиво.

Нури аль Малики также получает те же заказы от Петреуса. Он также должен сражаться. Но он политик, а не пехотный. Очевидно, он не может стрелять в своих политических врагов в голову. Поскольку Петреус дал ему виртуальный метод, Малики может реализовать свою собственную версию метода боя в соответствии с его конкретными обстоятельствами:

  • Найдите врага.
  • Попросите его арестовать несколько обвиненных BS.
  • Перейти на главную страницу
  • Пиво.

Иными словами, виртуальный метод предоставляет командные команды - но это общие инструкции, которые могут быть более конкретными для людей по иерархии армии в соответствии с их конкретными обстоятельствами.

Разница между двумя

  • Джордж Буш не доказывает детали реализации. Это должно быть сделано кем-то другим. Это абстрактный метод.

  • Petraeus, с другой стороны, предоставляет детали реализации, но он дал разрешение своим подчиненным переопределить свои заказы своей собственной версией, если они могут придумать что-то лучшее.

надеюсь, что это поможет.

2

Абстрактная функция не может иметь тело и ДОЛЖНА быть переопределена дочерними классами

Виртуальная функция будет иметь тело и может или не может быть переопределена дочерними классами

1

Абстрактная функция - это просто подпись, без реализации. Он используется в интерфейсе, чтобы объявить, как может использоваться класс. Он должен быть реализован в одном из производных классов.

Виртуальная функция (фактически метод) - это также функция, которую вы объявляете, и она должна быть реализована в одном из классов иерархии наследования.

Унаследованные экземпляры такого класса также наследуют реализацию, если вы ее не реализуете, в классе с более низкой иерархией.

1

Абстрактный метод не имеет реализации. Он объявлен в родительском классе. Дочерний класс ответственен за реализацию этого метода.

Виртуальный метод должен иметь реализацию в родительском классе, и это облегчает дочернему классу делать выбор, использовать ли эту реализацию родительского класса или иметь новую реализацию для этого метода в дочернем классе.

1

От общего объектно-ориентированного представления:

Относительно абстрактного метода. Когда вы помещаете абстрактный метод в родительский класс, вы говорите дочерним классам: Эй, обратите внимание, что у вас есть такая подпись метода. И если вы хотите использовать его, вы должны реализовать свои собственные!

Что касается виртуальной функции: когда вы помещаете виртуальный метод в родительский класс, вы говорите производным классам: Эй, здесь есть функциональность, которая что-то делает для вас. Если это полезно, просто используйте его. Если нет, переопределите это и внесите свой код, даже вы можете использовать мою реализацию в вашем коде!

это некоторая философия о различии между этими двумя понятиями в General OO

1

В С# нет ничего, что называется виртуальным классом.

Для функций

  1. Абстрактная функция имеет только сигнатуру, класс накопителя должен переопределяться функциональностью.
  2. Виртуальная функция будет содержать часть функциональности, которую класс привода может переопределить или не переопределить в соответствии с требованием

Вы можете решить с вашим требованием.

1

Ответ был предоставлен несколько раз, но вопрос о том, когда использовать каждый, - это решение времени разработки. Я считаю хорошей практикой попытаться объединить общие определения методов в разные интерфейсы и потянуть их в классы с соответствующими уровнями абстракции. Сбрасывание общего набора абстрактных и виртуальных определений методов в класс делает класс неустойчивым, когда лучше всего определить не-абстрактный класс, реализующий набор сжатых интерфейсов. Как всегда, это зависит от того, что лучше всего подходит вашим конкретным приложениям.

0

Здесь я пишу некоторый пример кода, надеясь, что это может быть довольно ощутимым примером, чтобы увидеть поведение интерфейсов, абстрактных классов и обычных классов на самом базовом уровне. Вы также можете найти этот код в 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(){
    //
    //    }
    }
}
0

Абстрактная функция или метод - это общедоступное "имя операции", предоставляемое классом, и его цель, наряду с абстрактными классами, в первую очередь заключается в предоставлении формы ограничения в проектировании объектов по отношению к структуре, которую должен реализовать объект.

Фактически классы, которые наследуются от его абстрактного класса, должны давать реализацию этому методу, обычно компиляторы выдают ошибки, когда они этого не делают.

Использование абстрактных классов и методов важно, главным образом, во избежание того, чтобы при проектировании классов, концентрируясь на деталях реализации, структура классов была слишком связана с реализациями, поэтому создавались зависимости и связи между классами, которые сотрудничают между ними.

Виртуальная функция или метод - это просто метод, который моделирует публичное поведение класса, но мы можем оставить его свободным для изменения в цепочке наследования, потому что мы думаем, что дочерние классы могут нуждаться в реализации некоторых конкретных расширений для этого поведения.

Они оба представляют форму полиморфизма в парадигме ориентации объекта.

Мы можем использовать абстрактные методы и виртуальные функции вместе для поддержки хорошей модели наследования.

Мы проектируем хорошую абстрактную структуру основных объектов нашего решения, затем создаем базовые реализации, находя их более склонными к дальнейшей специализации, и делаем их виртуальными, наконец, мы специализируем наши базовые реализации, в конечном итоге "переопределяя" унаследованные виртуальные.

0

Исходя из фона C++, С# virtual соответствует виртуальному C++, в то время как абстрактные методы С# соответствуют чисто виртуальной функции C++.

-4

Насколько я понимаю:

Абстрактные методы:

Только абстрактный класс может содержать абстрактные методы. Также производному классу необходимо реализовать метод, и реализация не реализуется в классе.

Виртуальные методы:

Класс может объявить их, а также обеспечить их реализацию. Также производному классу необходимо реализовать метод, чтобы переопределить его.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню