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

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

23 ответов


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

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


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

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

  1. только abstract классы могут иметь abstract членов.
  2. неabstract класс, который наследует от abstract класс должны override его abstract членов.
  3. An abstract член неявно virtual.
  4. An abstract member не может предоставить никакой реализации (abstract называется pure virtual в некоторых языках).

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

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

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

Абстрактную Функцию:

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

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

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

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

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

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

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


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

контекст

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

FireEscape()

  1. не собирать вещи
  2. прогулка к огню побег
  3. выйти из здания

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

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

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

  1. выполнить в окне
  2. выпрыгнуть в окно
  3. парашют благополучно на дно!--14-->

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

Аннотация методы

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

другими словами, каждый человек заставили разработать свой собственный метод 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 означает:

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

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

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


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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • абстрактный член неявно является виртуальным. Реферат может в некоторых языках его называют Чистым виртуальным.

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

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

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


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

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

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

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

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

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

  1. найти врага
  2. нейтрализовать его.
  3. есть пиво потом

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

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

  1. найти врага.
  2. стреляй ему в голову.
  3. Домой
  4. есть пиво.

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

  1. найти врага.
  2. арестуйте его с некоторыми сфабрикованными обвинениями.
  3. Домой
  4. есть пиво.

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

разница между двумя!--4-->

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

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

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


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

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

● Он не имеет тела.

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

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

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

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

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


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


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

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

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

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


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

для функции

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

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


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

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


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

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

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


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

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

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

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

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