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

StackOverflow https://stackoverflow.com/questions/391483

Вопрос

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

Это было полезно?

Решение

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

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

Другие советы

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

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

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

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. Ан abstract член неявно virtual.
  4. Ан abstract член не может предоставить какую-либо реализацию (abstract называется pure virtual на некоторых языках).

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

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

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

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

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

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

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

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

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

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

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

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

Контекст

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

Пожарный выход()

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

По сути, это виртуальный метод, называемый Пожарный выход()

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

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

  1. Беги к окну
  2. Выпрыгнуть из окна
  3. Безопасно спрыгните с парашютом на дно

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

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

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

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

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

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

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

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

  • Виртуальный означает, что мы МОЖЕМ его обойти.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. Найдите врага.
  2. Выстрелите ему в голову.
  3. Иди домой
  4. Выпейте пива.

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

  1. Найдите врага.
  2. Пусть его арестуют по каким-то сфабрикованным обвинениям.
  3. Иди домой
  4. Выпейте пива.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Для функций

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

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

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

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

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

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

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

С точки зрения 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(){
    //
    //    }
    }
}

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top