В чем разница между абстрактной функцией и виртуальной функцией? - PullRequest
1470 голосов
/ 24 декабря 2008

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

Ответы [ 26 ]

2556 голосов
/ 24 декабря 2008

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

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

271 голосов
/ 24 декабря 2008

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

Виртуальная функция обеспечивает реализацию по умолчанию и может существовать либо в абстрактном классе, либо в неабстрактном классе.

Так, например:

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();
}
76 голосов
/ 16 апреля 2009
  1. Только abstract классы могут иметь abstract членов.
  2. Не- abstract класс, который наследуется от abstract класса , должен override его abstract членов.
  3. abstract член неявно virtual.
  4. Член abstract не может обеспечить какую-либо реализацию (abstract в некоторых языках называется pure virtual).
58 голосов
/ 24 декабря 2008

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

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

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

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

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

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

  1. Он может быть объявлен как в абстрактном, так и в не абстрактном классе.
  2. Содержит реализацию метода.
  3. Может быть отменено.
29 голосов
/ 16 апреля 2009

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

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

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

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

25 голосов
/ 16 июня 2016

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

Context

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

FireEscape ()

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

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

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

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

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

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

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

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

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

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

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

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

22 голосов
/ 16 апреля 2009

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

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

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

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 голосов
/ 16 апреля 2009

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

В этом главное отличие.

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

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

...