Jaka jest różnica między funkcją abstrakcyjną a funkcją wirtualną? W jakich przypadkach zaleca się stosowanie wirtualnych lub abstrakcyjnych? Które z nich jest najlepsze?
Jaka jest różnica między funkcją abstrakcyjną a funkcją wirtualną? W jakich przypadkach zaleca się stosowanie wirtualnych lub abstrakcyjnych? Które z nich jest najlepsze?
Odpowiedzi:
Funkcja abstrakcyjna nie może mieć funkcji. Mówisz w zasadzie, że każda klasa potomna MUSI podać własną wersję tej metody, jednak zbyt ogólna jest nawet próba implementacji w klasie nadrzędnej.
Funkcja wirtualna to po prostu wygląd, oto funkcjonalność, która może, ale nie musi być wystarczająca dla klasy potomnej. Więc jeśli jest wystarczająco dobry, skorzystaj z tej metody, jeśli nie, zastąp mnie i zapewnij własną funkcjonalność.
Funkcja abstrakcyjna nie ma implementacji i można ją zadeklarować tylko w klasie abstrakcyjnej. Zmusza to klasę pochodną do zapewnienia implementacji.
Funkcja wirtualna zapewnia domyślną implementację i może istnieć w klasie abstrakcyjnej lub nieabstrakcyjnej.
Na przykład:
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
klasa nie musi w jakiś sposób implementować klasy abstrakcyjnej ? Nie robię tego często, więc mogę się mylić. Nie widzę tego w twoim przykładzie.
abstract
klasy mogą mieć abstract
członków.abstract
Klasa niebędąca dziedziczeniem po abstract
klasie musi mieć override
swoich abstract
członków.abstract
Członkiem jest niejawnie virtual
.abstract
Członek nie może zapewnić realizacji ( abstract
nazywany jest pure virtual
w niektórych językach).virtual
lub nie virtual
. Element abstract
członkowski (tj. Właściwość abstrakcyjna, metoda abstrakcyjna) jest podobny do metody wirtualnej, tzn. Można ją przesłonić, z tą różnicą, że nie ma ona domyślnej implementacji.
Zawsze musisz zastąpić funkcję abstrakcyjną.
A zatem:
Funkcja abstrakcyjna:
Funkcja wirtualna:
Metoda abstrakcyjna: jeśli klasa zawiera metodę abstrakcyjną, należy ją zadeklarować jako abstrakcyjną. Metoda abstrakcyjna nie ma implementacji, a zatem klasy wywodzące się z tej klasy abstrakcyjnej muszą zapewniać implementację tej metody abstrakcyjnej.
Metoda wirtualna: klasa może mieć metodę wirtualną. Metoda wirtualna ma implementację. Kiedy dziedziczą z klasy, która ma metodę wirtualną, to można zastąpić metodę wirtualną i zapewnić dodatkową logikę, lub wymienić logikę z własnej realizacji.
Kiedy stosować: W niektórych przypadkach wiesz, że niektóre typy powinny mieć określoną metodę, ale nie wiesz, jaką implementację powinna mieć ta metoda.
W takich przypadkach można utworzyć interfejs zawierający metodę z tym podpisem. Jeśli jednak masz taki przypadek, ale wiesz, że implementatorzy tego interfejsu będą mieli także inną wspólną metodę (dla której możesz już zapewnić implementację), możesz utworzyć klasę abstrakcyjną. Ta klasa abstrakcyjna zawiera następnie metodę abstrakcyjną (którą należy zastąpić) i inną metodę, która zawiera logikę „wspólną”.
Metodę wirtualną należy zastosować, jeśli masz klasę, której można użyć bezpośrednio, ale dla której chcesz, aby spadkobiercy mogli zmieniać określone zachowanie, chociaż nie jest to obowiązkowe.
wyjaśnienie: z analogiami. mam nadzieję, że ci to pomoże.
Kontekst
Pracuję na 21 piętrze budynku. I jestem paranoikiem ognia. Co jakiś czas, gdzieś na świecie, ogień spala skrobak do nieba. Ale na szczęście mamy gdzieś tutaj instrukcję dotyczącą postępowania w przypadku pożaru:
Wyjście pożarowe()
Jest to w zasadzie wirtualna metoda o nazwie FireEscape ()
Metoda wirtualna
Ten plan jest całkiem dobry na 99% okoliczności. To podstawowy plan, który działa. Ale istnieje 1% szansy na zablokowanie lub uszkodzenie wyjścia ewakuacyjnego, w którym to przypadku jesteś całkowicie wkręcony i staniesz się toastem, chyba że podejmiesz drastyczne działania. Za pomocą metod wirtualnych możesz to zrobić: możesz zastąpić podstawowy plan FireEscape () własną wersją planu:
Innymi słowy, metody wirtualne zapewniają podstawowy plan, który można zastąpić w razie potrzeby . Podklasy mogą przesłonić metodę wirtualną klasy nadrzędnej, jeśli programista uzna to za stosowne.
Metody abstrakcyjne
Nie wszystkie organizacje są dobrze wywiercone. Niektóre organizacje nie przeprowadzają ćwiczeń przeciwpożarowych. Nie mają ogólnej polityki ucieczki. Każdy człowiek jest dla siebie. Zarząd jest zainteresowany tylko taką polityką.
Innymi słowy, każda osoba jest zmuszona opracować własną metodę FireEscape (). Jeden facet wyjdzie z wyjścia ewakuacyjnego. Kolejny facet spadnie ze spadochronem. Inny facet użyje technologii napędu rakietowego, aby odlecieć z budynku. Kolejny facet zejdzie na ląd. Kierownictwo nie dba o to, jak uciekniesz, o ile masz podstawowy plan FireEscape () - jeśli nie, możesz mieć gwarancję, że BHP spadnie na organizację jak tona cegieł. To właśnie należy rozumieć metodą abstrakcyjną.
Jaka jest różnica między nimi ponownie?
Metoda abstrakcyjna: podklasy są zmuszone do implementacji własnej metody FireEscape. Dzięki metodzie wirtualnej czeka na Ciebie podstawowy plan, ale możesz go wdrożyć, jeśli nie jest wystarczająco dobry.
To nie było takie trudne, prawda?
Metoda abstrakcyjna to metoda, którą należy zaimplementować, aby stworzyć konkretną klasę. Deklaracja należy do klasy abstrakcyjnej (a każda klasa z metodą abstrakcyjną musi być klasą abstrakcyjną) i musi być zaimplementowana w konkretnej klasie.
Metoda wirtualna to metoda, którą można przesłonić w klasie pochodnej za pomocą przesłonięcia, zastępując zachowanie w nadklasie. Jeśli nie przesłonisz, uzyskasz oryginalne zachowanie. Jeśli to zrobisz, zawsze otrzymasz nowe zachowanie. W przeciwieństwie do metod nie wirtualnych, których nie można zastąpić, ale można ukryć oryginalną metodę. Odbywa się to za pomocą new
modyfikatora.
Zobacz następujący przykład:
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");
}
}
Kiedy tworzę instancję DerivedClass
i dzwonię SayHello
, albo SayGoodbye
dostaję „Cześć” i „Do zobaczenia później”. Jeśli zadzwonię HelloGoodbye
, dostanę „Cześć” i „Do zobaczenia później”. Jest tak, ponieważ SayGoodbye
jest wirtualny i można go zastąpić klasami pochodnymi. SayHello
jest tylko ukryty, więc kiedy wywołuję to z mojej klasy podstawowej, otrzymuję moją oryginalną metodę.
Metody abstrakcyjne są domyślnie wirtualne. Definiują zachowanie, które musi być obecne, podobnie jak interfejs.
Metody abstrakcyjne są zawsze wirtualne. Nie mogą mieć implementacji.
To główna różnica.
Zasadniczo użyłbyś wirtualnej metody, jeśli masz jej „domyślną” implementację i chcesz pozwolić potomnym na zmianę jej zachowania.
Metodą abstrakcyjną zmuszasz potomków do zapewnienia implementacji.
Uprościłem to, wprowadzając ulepszenia w następujących klasach (z innych odpowiedzi):
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");
}
}
}
Wiązanie to proces mapowania nazwy na jednostkę kodu.
Późne wiązanie oznacza, że używamy nazwy, ale odraczamy mapowanie. Innymi słowy, najpierw tworzymy / wspominamy nazwę i pozwalamy, aby jakiś późniejszy proces obsługiwał mapowanie kodu na tę nazwę.
Teraz rozważ:
Tak więc krótka odpowiedź brzmi: virtual
jest późną instrukcją wiązania dla maszyny (środowiska wykonawczego), podczas gdy abstract
jest późną instrukcją wiązania dla człowieka (programisty)
Innymi słowy virtual
oznacza:
„Drogi środowisku wykonawczym , powiąż odpowiedni kod z tą nazwą, robiąc to, co robisz najlepiej: wyszukiwanie ”
abstract
Oznacza natomiast :
„Drogi programatorze , powiąż odpowiedni kod z tą nazwą, robiąc to, co robisz najlepiej: wymyślając ”
Dla zachowania kompletności przeciążenie oznacza:
„Drogi kompilatorze , powiąż odpowiedni kod z tą nazwą, robiąc to, co robisz najlepiej: sortowanie ”.
Metoda wirtualna :
Wirtualny oznacza, że MOŻEMY to zastąpić.
Funkcja wirtualna ma implementację. Gdy odziedziczymy klasę, możemy zastąpić funkcję wirtualną i podać własną logikę.
Metoda abstrakcyjna
Abstrakt oznacza, że MUSIMY go zastąpić.
Funkcja abstrakcyjna nie ma implementacji i musi należeć do klasy abstrakcyjnej.
Można to tylko zadeklarować. Zmusza to klasę pochodną do zapewnienia jej implementacji.
Członek abstrakcyjny jest domyślnie wirtualny. Abstrakt można nazwać czystym wirtualnym w niektórych językach.
public abstract class BaseClass
{
protected abstract void xAbstractMethod();
public virtual void xVirtualMethod()
{
var x = 3 + 4;
}
}
Widziałem w niektórych miejscach metodę abstrakcyjną zdefiniowaną jak poniżej. **
„Metoda abstrakcyjna musi zostać zaimplementowana w klasie potomnej”
** Czułem, że to jest.
Nie jest konieczne, aby metoda abstrakcyjna musiała zostać zaimplementowana w klasie potomnej, jeśli klasa potomna jest również abstrakcyjna .
1) Metoda abstrakcyjna nie może być metodą prywatną. 2) Metoda abstrakcyjna nie może być zaimplementowana w tej samej klasie abstrakcyjnej.
Powiedziałbym ... jeśli wdrażamy klasę abstrakcyjną, musisz zastąpić metody abstrakcyjne z podstawowej klasy abstrakcyjnej. Ponieważ .. Implementacja metody abstrakcyjnej polega na zastąpieniu słowa kluczowego. Podobna do metody wirtualnej.
Metoda wirtualna nie musi być implementowana w odziedziczonej klasie.
----------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();
}
}
Większość powyższych przykładów używa kodu - i są one bardzo, bardzo dobre. Nie muszę dodawać do tego, co mówią, ale poniżej znajduje się proste objaśnienie, które wykorzystuje analogie, a nie kod / terminy techniczne.
Proste objaśnienie - objaśnienie za pomocą analogii
Metoda abstrakcyjna
Pomyśl George W. Bush. Mówi do swoich żołnierzy: „Idź walczyć w Iraku”. I to wszystko. Wszystko, co określił, to konieczność walki. Nie określa, jak dokładnie to się stanie. Ale nie można po prostu wyjść i „walczyć”: co to dokładnie znaczy? czy walczę z B-52 czy z moim derringerem? Te szczegółowe informacje pozostawia się komuś innemu. To jest metoda abstrakcyjna.
Metoda wirtualna
David Petraeus jest wysoko w wojsku. Zdefiniował, co oznacza walka:
Problem polega na tym, że jest to bardzo ogólna metoda. To dobra metoda, która działa, ale czasami nie jest wystarczająco szczegółowa. Dobrą rzeczą dla Petraeusa jest to, że jego rozkazy mają swobodę działania i zakres - pozwolił innym zmienić jego definicję „walki”, zgodnie z ich szczególnymi wymaganiami.
Prywatna praca Bloggs czyta zamówienie Petraeusa i otrzymuje pozwolenie na wdrożenie własnej wersji walki, zgodnie z jego szczególnymi wymaganiami:
Nouri al Maliki również otrzymuje te same zamówienia od Petraeusa. On też ma walczyć. Ale jest politykiem, a nie piechotą. Oczywiście nie może chodzić i strzelać w głowę swoim politycznym wrogom. Ponieważ Petraeus dał mu wirtualną metodę, Maliki może wdrożyć własną wersję metody walki, w zależności od jego szczególnych okoliczności:
Innymi słowy, metoda wirtualna dostarcza instrukcji na tablicy - ale są to instrukcje ogólne, które mogą być bardziej szczegółowe dla osób z dziedzicznej armii, w zależności od ich szczególnych okoliczności.
Różnica między nimi
George Bush nie potwierdza żadnych szczegółów implementacyjnych. Musi to zapewnić ktoś inny. To jest metoda abstrakcyjna.
Petraeus z drugiej strony ma podać szczegóły implementacji, ale dał pozwolenie na swoich podwładnych, aby zastąpić jego rozkazy z własnej wersji, czy mogą wymyślić coś lepszego.
mam nadzieję, że to pomaga.
Funkcja abstrakcyjna (metoda):
● Metoda abstrakcyjna to metoda zadeklarowana za pomocą słowa kluczowego streszczenie.
● Nie ma ciała.
● Powinien zostać zaimplementowany przez klasę pochodną.
● Jeśli metoda jest abstrakcyjna, klasa powinna abstrakować.
funkcja wirtualna (metoda):
● Metoda wirtualna to metoda zadeklarowana za pomocą słowa kluczowego virtual i może być zastąpiona przez metodę klasy pochodnej za pomocą słowa kluczowego override.
● Od klasy pochodnej zależy, czy ją zastąpić, czy nie.
Odpowiedź była udzielana wiele razy, ale pytanie o to, kiedy użyć każdej z nich, jest decyzją w czasie projektowania. Uważam, że dobrą praktyką jest łączenie wspólnych definicji metod w odrębne interfejsy i wciąganie ich do klas na odpowiednich poziomach abstrakcji. Zrzucenie wspólnego zestawu abstrakcyjnych i wirtualnych definicji metod do klasy sprawia, że klasa staje się niemożliwa do ustalenia, kiedy najlepiej zdefiniować nieabstrakcyjną klasę, która implementuje zestaw zwięzłych interfejsów. Jak zawsze zależy to od tego, co najlepiej odpowiada konkretnym potrzebom aplikacji.
Funkcja abstrakcyjna nie może mieć ciała i MUSI być nadpisana przez klasy potomne
Funkcja wirtualna będzie miała ciało i może zostać zastąpiona przez klasy potomne
Z ogólnego widoku obiektowego:
Odnośnie metody abstrakcyjnej : Kiedy umieścisz metodę abstrakcyjną w klasie nadrzędnej, tak naprawdę mówisz do klas podrzędnych: Hej, zauważ, że masz taką sygnaturę metody. A jeśli chcesz go użyć, powinieneś wdrożyć własne!
Odnośnie funkcji wirtualnej : Kiedy umieścisz metodę wirtualną w klasie nadrzędnej, mówisz do klas pochodnych: Hej, jest tu funkcjonalność, która coś dla ciebie robi. Jeśli jest to przydatne, po prostu go użyj. Jeśli nie, zastąp to i zaimplementuj swój kod, nawet ty możesz użyć mojej implementacji w swoim kodzie!
to jest jakaś filozofia na temat różnic pomiędzy tą dwiema koncepcjami w Generalnym OO
Funkcja abstrakcyjna to „tylko” podpis, bez implementacji. Jest on używany w interfejsie, aby zadeklarować sposób użycia klasy. Musi być zaimplementowany w jednej z pochodnych klas.
Funkcja wirtualna (właściwie metoda) jest również funkcją, którą deklarujesz i powinna zostać zaimplementowana w jednej z klas hierarchii dziedziczenia.
Dziedziczone wystąpienia takiej klasy również dziedziczą implementację, chyba że ją zaimplementujesz, w niższej klasie hierarchicznej.
W języku C # nie ma żadnych wywołań klas wirtualnych.
Dla funkcji
Możesz zdecydować na podstawie swoich wymagań.
Metoda abstrakcyjna nie ma implementacji, jest zadeklarowana w klasie nadrzędnej. Klasa potomna odpowiada za implementację tej metody.
Metoda wirtualna powinna mieć implementację w klasie nadrzędnej i ułatwia klasie podrzędnej dokonanie wyboru, czy użyć tej implementacji klasy nadrzędnej, czy mieć nową implementację dla tej metody w klasie podrzędnej.
Abstrakcyjna funkcja lub metoda jest publiczną „nazwą operacji” ujawnioną przez klasę, jej cel, wraz z klasami abstrakcyjnymi, stanowi przede wszystkim formę ograniczenia w projektowaniu obiektów w stosunku do struktury, którą obiekt musi zaimplementować.
W rzeczywistości klasy, które dziedziczą po klasie abstrakcyjnej, muszą podać implementację tej metody, generalnie kompilatory zgłaszają błędy, gdy tego nie robią.
Korzystanie z klas i metod abstrakcyjnych jest ważne przede wszystkim, aby tego uniknąć, ponieważ koncentrując się na szczegółach implementacji podczas projektowania klas, struktura klas jest zbyt powiązana z implementacjami, tworząc w ten sposób zależności i łącząc klasy, które ze sobą współpracują.
Wirtualna funkcja lub metoda jest po prostu metodą modelującą publiczne zachowanie klasy, ale możemy ją dowolnie modyfikować w łańcuchu dziedziczenia, ponieważ uważamy, że klasy potomne mogą wymagać zaimplementowania określonych rozszerzeń dla tego zachowania.
Obie reprezentują formę polimorfizmu w paradygmacie orientacji obiektowej.
Możemy używać razem metod abstrakcyjnych i funkcji wirtualnych do obsługi dobrego modelu dziedziczenia.
Projektujemy dobrą abstrakcyjną strukturę głównych obiektów naszego rozwiązania, następnie tworzymy podstawowe implementacje, lokalizując te bardziej podatne na dalsze specjalizacje i wykonujemy je jako wirtualne, w końcu specjalizujemy się w naszych podstawowych implementacjach, ostatecznie „zastępując” odziedziczone wirtualne.
Piszę tutaj przykładowy kod z nadzieją, że może to być namacalny przykład, aby zobaczyć zachowania interfejsów, klas abstrakcyjnych i zwykłych klas na bardzo podstawowym poziomie. Możesz również znaleźć ten kod w github jako projekt, jeśli chcesz go użyć jako wersji demonstracyjnej: 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(){
//
// }
}
}
W moim rozumieniu:
Metody abstrakcyjne:
Tylko klasa abstrakcyjna może przechowywać metody abstrakcyjne. Również klasa pochodna musi zaimplementować metodę, a klasa nie zapewnia żadnej implementacji.
Metody wirtualne:
Klasa może je zadeklarować, a także zapewnić ich implementację. Również klasa pochodna musi zaimplementować metodę, aby ją zastąpić.