Чим відрізняється абстрактна функція від віртуальної функції? У яких випадках рекомендується використовувати віртуальний або абстрактний? Який із них найкращий підхід?
Чим відрізняється абстрактна функція від віртуальної функції? У яких випадках рекомендується використовувати віртуальний або абстрактний? Який із них найкращий підхід?
Відповіді:
Абстрактна функція не може мати функціональних можливостей. Ви в основному говорите, будь-який дочірній клас ОБОВ'ЯЗКОВО повинен дати власну версію цього методу, однак це занадто загально, щоб навіть намагатися реалізувати у батьківському класі.
Віртуальна функція , по суті кажучи, виглядає, ось функціональність, яка може бути або не бути достатньою для дочірнього класу. Тож якщо це досить добре, використовуйте цей метод, якщо ні, то перекрийте мене та надайте власну функціональність.
Абстрактна функція не має реалізації, і її можна оголосити лише на абстрактному класі. Це змушує похідний клас забезпечити реалізацію.
Віртуальна функція забезпечує реалізацію за замовчуванням, і вона може існувати як в абстрактному класі, так і в нео абстрактному класі.
Так, наприклад:
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();
}
MyBase
клас якось реалізувати абстрактний клас? Я не роблю цього часто, тому можу помилитися. Я не бачу цього у вашому прикладі.
abstract
можуть мати лише класи abstract
.abstract
який успадковує abstract
клас, повинен бути override
його abstract
членами.abstract
Член неявно virtual
.abstract
не може надати жодної реалізації ( abstract
викликається pure virtual
на деяких мовах).virtual
чи не virtual
. abstract
Елемент (тобто абстрактного властивості, абстрактний метод) точно так само як віртуальний метод, тобто ви можете змінити його, за винятком того, що він не несе з собою реалізацію за замовчуванням.
Ви завжди повинні перекривати абстрактну функцію.
Таким чином:
Абстрактна функція:
Віртуальна функція:
Абстрактний метод: Коли клас містить абстрактний метод, цей клас повинен бути оголошений абстрактним. Абстрактний метод не має реалізації, і тому класи, що походять від цього абстрактного класу, повинні забезпечувати реалізацію цього абстрактного методу.
Віртуальний метод: Клас може мати віртуальний метод. Віртуальний метод має реалізацію. Коли ви успадковуєте клас, у якого є віртуальний метод, ви можете перекрити віртуальний метод і надати додаткову логіку або замінити логіку на власну реалізацію.
Коли використовувати що: У деяких випадках ви знаєте, що певні типи повинні мати певний метод, але ви не знаєте, якою реалізацією повинен володіти цей метод.
У таких випадках ви можете створити інтерфейс, який містить метод з цією підписом. Однак, якщо у вас є такий випадок, але ви знаєте, що в реалізації цього інтерфейсу буде також інший загальний метод (для якого ви вже можете надати реалізацію), ви можете створити абстрактний клас. Потім цей абстрактний клас містить абстрактний метод (який слід переосмислити) та інший метод, який містить "загальну" логіку.
Віртуальний метод слід використовувати, якщо у вас є клас, який можна використовувати безпосередньо, але для якого ви хочете, щоб спадкоємці могли змінити певну поведінку, хоча це не є обов'язковим.
пояснення: з аналогіями. сподіваємось, це допоможе тобі.
Контекст
Я працюю на 21 поверсі будинку. І я параноїчний щодо вогню. Раз і десь у світі десь у світі палає вогонь по небосхилу. Але на щастя, тут десь інструкція з інструкцій, що робити у випадку пожежі:
Пожежний вихід()
Це в основному віртуальний метод під назвою FireEscape ()
Віртуальний метод
Цей план є досить вдалим для 99% обставин. Це основний план, який працює. Але є 1% шанс, що пожежна втеча буде заблокована або пошкоджена, і в цьому випадку ви повністю накрутитеся, і ви отримаєте тост, якщо не вживатимете різких заходів. За допомогою віртуальних методів ви можете зробити саме це: ви можете змінити основний план FireEscape () за допомогою власної версії плану:
Іншими словами, віртуальні методи забезпечують базовий план, який при необхідності можна змінити . Підкласи можуть замінити віртуальний метод батьківського класу, якщо програміст вважає це доцільним.
Абстрактні методи
Не всі організації добре пробудовані. Деякі організації не роблять протипожежних заходів. Вони не мають загальної політики втечі. Кожна людина - сама для себе. Керівництво зацікавлене лише в такій політиці, яка існує.
Іншими словами, кожна людина змушена розробляти свій власний метод FireEscape (). Один хлопець вийде з пожежної втечі. Ще один хлопець буде парашутувати. Інший хлопець використовуватиме ракетну технологію, щоб відлетіти від будівлі. Ще один хлопець відмовиться. Керівництву не важливо, як ви втечете, якщо у вас є основний план FireEscape () - якщо вони не будуть, вам можна гарантувати, що OHS зійде на організацію, як тонну цегли. Це те, що мається на увазі під абстрактним методом.
Яка різниця між ними знову?
Абстрактний метод: підкласи змушені реалізувати власний метод FireEscape. З віртуальним методом у вас чекає базовий план, але ви можете вибрати реалізувати свій власний, якщо він недостатньо хороший.
Тепер це було не так важко?
Абстрактний метод - це метод, який необхідно реалізувати, щоб скласти конкретний клас. Декларація знаходиться в абстрактному класі (і будь-який клас з абстрактним методом повинен бути абстрактним класом) і він повинен бути реалізований у конкретному класі.
Віртуальний метод - це метод, який може бути замінений у похідному класі за допомогою override, замінивши поведінку в суперкласі. Якщо ви не переможете, ви отримаєте оригінальну поведінку. Якщо ви це робите, ви завжди отримуєте нову поведінку. Це протилежно не віртуальним методам, які не можна перекрити, але можуть приховати оригінальний метод. Це робиться за допомогою 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
означає:
"Шановний програміст , будь ласка, прив'яжіть відповідний код до цього імені, роблячи те, що вам найкраще: придумуючи "
Для повноти перевантаження означає:
"Шановний компілятор , прив'яжіть відповідний код до цього імені, роблячи те, що вам найкраще: сортування ".
Віртуальний метод :
Віртуальне означає, що ми МОЖЕ її перекрити.
Віртуальна функція має реалізацію. Коли ми успадковуємо клас, ми можемо замінити віртуальну функцію та надати власну логіку.
Абстрактний метод
Анотація означає, що ми МОЖЕМЕ її перекрити
Абстрактна функція не має реалізації і повинна бути в абстрактному класі.
Це можна лише задекларувати. Це змушує похідний клас забезпечити його реалізацію.
Абстрактний член неявно віртуальний. Реферат можна назвати чистим віртуальним у деяких мовах.
public abstract class BaseClass
{
protected abstract void xAbstractMethod();
public virtual void xVirtualMethod()
{
var x = 3 + 4;
}
}
Я бачив, де в деяких місцях абстрактний метод визначається як нижче. **
"Абстрактний метод повинен бути реалізований у дочірньому класі"
** Я відчув, що це як.
Не обов’язково, щоб абстрактний метод повинен бути реалізований у дитячому класі, якщо дочірній клас також абстрактний .
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();
}
}
У більшості наведених вище прикладів використовується код - і вони дуже дуже хороші. Мені не потрібно додавати те, що вони говорять, але наступне - просте пояснення, яке використовує аналогії, а не код / технічні терміни.
Просте пояснення - пояснення за допомогою аналогій
Абстрактний метод
Подумайте, Джордж Буш. Він каже своїм солдатам: "Іди воюй в Іраку". І це все. Все, що він зазначив, - це те, що потрібно вести боротьбу. Він не уточнює, як саме це станеться. Але я маю на увазі, ви не можете просто вийти і «битися»: що це означає саме? чи я б'юся з B-52 чи моїм деррінгером? Ці конкретні деталі залишаються комусь іншим. Це абстрактний метод.
Віртуальний метод
Давид Петрей високий в армії. Він визначив, що означає боротьба:
Проблема в тому, що це дуже загальний метод. Це хороший метод, який працює, але іноді недостатньо конкретний. Добре для Петрая полягає в тому, що його накази мають свободу та масштаби - він дозволив іншим змінити його визначення "воювати", відповідно до їх особливих вимог.
Приватний робочий блог читає наказ Петра і отримує дозвіл на реалізацію власної версії боротьби відповідно до його особливих вимог:
Норі аль Малікі також отримує ті ж замовлення від Петрая. Він також повинен боротися. Але він - політик, а не піхота. Очевидно, він не може обійтись, стріляючи в голову своїх політичних ворогів. Оскільки Петрей дав йому віртуальний метод, то Малікі може реалізувати власну версію методу боротьби відповідно до його конкретних обставин:
Іншими словами, віртуальний метод дає інструкції на котлах - але це загальні вказівки, які можуть бути більш конкретизовані людьми в армійській іерархії відповідно до їх конкретних обставин.
Різниця між ними
Джордж Буш не доводить жодних деталей щодо імплементації. Це повинен надати хтось інший. Це абстрактний метод.
З іншого боку, Петрей наводить детальну інформацію про імплементацію, але він надав дозвіл своїм підлеглим переосмислювати його замовлення за їх власною версією, якщо вони можуть придумати щось краще.
сподівання, що допомагає.
Абстрактна функція (метод):
● Абстрактний метод - це метод, який оголошується ключовим словом абстракт.
● У ньому немає тіла.
● Він повинен бути реалізований похідним класом.
● Якщо метод абстрактний, то клас повинен абстрагуватися.
віртуальна функція (метод):
● Віртуальний метод - це метод, який оголошується за допомогою ключового слова virtual, і його можна замінити методом похідного класу за допомогою ключового слова override.
● Виправданий клас залежить від того, переосмислити його чи ні.
Відповідь було надано неодноразово, але питання про те, коли використовувати їх, є рішенням, що стосується дизайну. Я вважаю б це доброю практикою намагатися поєднати загальні визначення методів у різні інтерфейси та перетягнути їх на класи на відповідних рівнях абстракції. Демпінг загального набору абстрактних і віртуальних визначень методів у клас робить клас нерозбірливим, коли, можливо, найкраще визначити неабразивний клас, який реалізує набір стислих інтерфейсів. Як завжди, це залежить від того, що найкраще відповідає вашим програмам.
Абстрактна функція не може мати тіла, і ОБОВ'ЯЗКОВО перекривати дошкільні класи
Віртуальна функція матиме тіло і може або не може бути відмінена дітьми класами
З загального об'єктно-орієнтованого погляду:
Щодо абстрактного методу : Коли ви вводите абстрактний метод у батьківський клас, фактично ви говорите дочірнім класам: Привіт, зауважте, що у вас є такий підпис методу. І якщо ви хочете його використовувати, ви повинні реалізувати своє!
Щодо віртуальної функції : Коли ви кладете віртуальний метод у батьківський клас, ви говорите похідним класам: Ей, тут є функціонал, який щось робить для вас. Якщо це корисно для вас, просто використовуйте його. Якщо ні, скасуйте це і реалізуйте свій код, навіть ви можете використовувати мою реалізацію у своєму коді!
це деяка філософія про різні між цими двома концепціями в General OO
Абстрактна функція - це "просто" підпис, без реалізації. Він використовується в інтерфейсі для оголошення способу використання класу. Він повинен бути реалізований в одному з похідних класів.
Віртуальна функція (фактично метод) - це функція, яку ви також декларуєте і яка повинна бути реалізована в одному з класів ієрархії спадкування.
Спадкові екземпляри такого класу також успадковують реалізацію, якщо ви її не реалізуєте, у нижчому класі ієрархії.
У C # немає віртуального класу викликів.
Для функцій
Ви можете вирішити зі своєю вимогою.
Абстрактний метод не має реалізації. Він оголошений у батьківському класі. Дочірній клас відповідальний за реалізацію цього методу.
Віртуальний метод повинен мати реалізацію в батьківському класі, і це полегшує дочірньому класу зробити вибір, чи використовувати цю реалізацію батьківського класу, чи мати нову реалізацію для цього методу в дочірньому класі.
Абстрактна функція або метод - це загальнодоступне "ім'я операції", яке піддається класу, його мета, поряд з абстрактними класами, в першу чергу забезпечують форму обмеження в дизайні об'єктів щодо структури, яку об'єкт повинен реалізувати.
Насправді класи, які успадковують його абстрактний клас, повинні реалізувати цей метод, як правило, компілятори створюють помилки, коли цього не роблять.
Використання абстрактних класів та методів важливо здебільшого уникати того, щоб, орієнтуючись на деталі реалізації під час проектування класів, структура класів була надто пов'язана з реалізаціями, тому створюючи залежності та зв’язок між класами, які співпрацюють між ними.
Віртуальна функція або метод - це просто метод, який моделює публічну поведінку класу, але ми можемо залишити вільні зміни в ланцюжку спадкування, тому що ми вважаємо, що дочірні класи могли потребувати впровадження певних розширень для такої поведінки.
Вони обоє являють собою форму поліморффізму в парадигмі орієнтації на об'єкт.
Ми можемо використовувати абстрактні методи та віртуальні функції разом для підтримки хорошої моделі успадкування.
Ми розробляємо хорошу абстрактну структуру основних об'єктів нашого рішення, потім створюємо базові реалізації, розміщуючи тих, хто більш схильний до подальших спеціалізацій, і робимо їх як віртуальні, нарешті спеціалізуємося на наших основних реалізаціях, події, що «переосмислюють» успадковані віртуальні.
Тут я пишу деякий зразок коду, сподіваючись, що це може бути досить відчутним прикладом, щоб побачити поведінку інтерфейсів, абстрактних класів та звичайних класів на дуже базовому рівні. Ви також можете знайти цей код у github як проект, якщо ви хочете використовувати його як демонстрацію: https://github.com/usavas/JavaAb абстрактAndInterfaceDemo
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(){
//
// }
}
}
Наскільки я розумію:
Абстрактні методи:
Тільки абстрактний клас може містити абстрактні методи. Також похідному класу потрібно реалізувати метод, і в ньому не передбачено жодної реалізації.
Віртуальні методи:
Клас може оголосити їх, а також забезпечити реалізацію того ж. Також похідному класу потрібно реалізувати метод, щоб його перекрити.