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

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

вопрос задан 24.12.2008
Moran
7329 репутация

23 ответов


  • 2362 рейтинг

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

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

    ответ дан BFree, с репутацией 83028, 24.12.2008
  • 252 рейтинг

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

    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();
    }
    
    ответ дан JoshBerke, с репутацией 52960, 24.12.2008
  • 70 рейтинг
    1. Только abstract классов могут иметь abstract членов.
    2. Класс, не относящийся к abstract, который наследуется от класса abstract, должен override его членов abstract.
    3. Член abstract неявно virtual.
    4. Член abstract не может обеспечить какую-либо реализацию (abstract в некоторых языках называется pure virtual).
    ответ дан Mehrdad Afshari, с репутацией 335708, 16.04.2009
  • 51 рейтинг

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

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

    • Абстрактные функции - когда наследник должен предоставить свою собственную реализацию
    • Виртуальный - когда , то наследник принимает решение
    ответ дан Rinat Abdullin, с репутацией 18161, 24.12.2008
  • 30 рейтинг

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

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

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

    1. Он может быть объявлен как в абстрактном, так и в не абстрактном классе.
    2. Содержит реализацию метода.
    3. Это может быть отменено.
    ответ дан Lexnim, с репутацией 301, 28.05.2014
  • 27 рейтинг

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

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

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

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

    ответ дан Frederik Gheysels, с репутацией 48338, 16.04.2009
  • 23 рейтинг

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

    Контекст

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

    FireEscape ()

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

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

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

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

    1. Запустить к окну
    2. Выпрыгнуть в окно
    3. Парашют благополучно на дно

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

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

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

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

    В чем разница между двумя снова?

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

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

    ответ дан BKSpurgeon, с репутацией 9936, 16.06.2016
  • 21 рейтинг

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

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

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

    ответ дан Kamiel Wanrooij, с репутацией 8240, 16.04.2009
  • 9 рейтинг

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

    Это главное отличие.

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

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

    ответ дан Rashack, с репутацией 4104, 16.04.2009
  • 9 рейтинг

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

    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");
            }
        }
    }
    
    ответ дан MeqDotNet, с репутацией 510, 7.12.2011
  • 4 рейтинг

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

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

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

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

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

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

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

    , тогда как abstract означает:

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

    Ради полноты перегрузка означает:

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

    ответ дан Rodrick Chapman, с репутацией 4482, 13.08.2017
  • 3 рейтинг

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

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

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

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

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

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

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

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

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

      public abstract class BaseClass
      { 
          protected abstract void xAbstractMethod();
      
          public virtual void xVirtualMethod()
          {
              var x = 3 + 4;
          }
      } 
      
    ответ дан flik, с репутацией 833, 25.03.2018
  • 3 рейтинг

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

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

    ответ дан Brann, с репутацией 17371, 16.04.2009
  • 3 рейтинг

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

    «Абстрактный метод должен быть реализован в дочернем классе»

    ** Я чувствовал, что это как.

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

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

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

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

                                     ----------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();
        }
    }
    
    ответ дан Kodoth, с репутацией 72, 5.08.2015
  • 2 рейтинг

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

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

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

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

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

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

    1. Найди врага
    2. Нейтрализовать его.
    3. Выпить пива после

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

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

    1. Найти врага.
    2. Стреляй ему в голову.
    3. Иди домой
    4. Есть пиво.

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

    1. Найти врага.
    2. У него арестовали с некоторыми сфабрикованными обвинениями.
    3. Иди домой
    4. Есть пиво.

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

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

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

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

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

    ответ дан BKSpurgeon, с репутацией 9936, 6.05.2016
  • 2 рейтинг

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

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

    ответ дан Yeasin Abedin Siam, с репутацией 771, 12.01.2016
  • 2 рейтинг

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

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

    ● У него нет корпуса.

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

    ● Если метод является абстрактным, тогда класс должен быть абстрактным.

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

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

    ● Производный класс должен переопределять его или нет.

    ответ дан Kedarnath M S, с репутацией 49, 31.05.2016
  • 1 рейтинг

    Из общего объектно-ориентированного вида:

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

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

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

    ответ дан Mohammad Nikravesh, с репутацией 318, 1.03.2017
  • 1 рейтинг

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

    ответ дан ComeIn, с репутацией 813, 19.08.2013
  • 1 рейтинг

    В C # нет ничего вызывающего виртуальный класс.

    Для функций

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

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

    ответ дан Nithila Shanmugananthan, с репутацией 193, 7.06.2016
  • 0 рейтинг

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

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

    ответ дан Vinay Chanumolu, с репутацией 31, 5.06.2018
  • 0 рейтинг

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

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

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

    ответ дан Sagi Berco, с репутацией 1, 27.07.2018
  • -2 рейтинг

    В моем понимании:

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

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

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

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

    ответ дан Qaiser, с репутацией 7, 27.06.2011