Was ist der Unterschied zwischen einer abstrakten Methode und einer virtuellen Methode? In welchen Fällen ist es empfehlenswert, abstrakte oder virtuelle Methoden zu verwenden? Welcher Ansatz ist der beste?
Antworten
Zu viele Anzeigen?Erklärung: mit analogien. hoffentlich hilft es ihnen.
Kontext
Ich arbeite im 21. Stock eines Gebäudes. Und ich bin paranoid wegen Feuer. Ab und zu bricht irgendwo auf der Welt ein Feuer aus, das einen Wolkenkratzer niederbrennt. Aber zum Glück haben wir hier irgendwo eine Gebrauchsanweisung, was im Brandfall zu tun ist:
FeuerFlucht()
- Sammeln Sie keine Habseligkeiten
- Gang zur Feuerleiter
- Verlassen des Gebäudes
Dies ist im Grunde eine virtuelle Methode namens FeuerFlucht()
Virtuelle Methode
Dieser Plan ist für 99 % der Fälle gut geeignet. Es ist ein Basisplan, der funktioniert. Aber es gibt eine 1 %ige Chance, dass die Feuerleiter blockiert oder beschädigt ist. In diesem Fall sind Sie völlig aufgeschmissen und werden getoastet, wenn Sie keine drastischen Maßnahmen ergreifen. Mit virtuellen Methoden können Sie genau das tun: Sie können den Basisplan FireEscape() mit Ihrer eigenen Version des Plans überschreiben:
- Zum Fenster laufen
- Aus dem Fenster springen
- Mit dem Fallschirm sicher in die Tiefe springen
Mit anderen Worten virtuelle Methoden bieten einen Basisplan, der bei Bedarf überschrieben werden kann . Unterklassen können die virtuelle Methode der Elternklasse außer Kraft setzen, wenn der Programmierer dies für angemessen hält.
Abstrakte Methoden
Nicht alle Organisationen sind gut gebohrt. Einige Organisationen führen keine Brandschutzübungen durch. Sie haben keine übergreifende Fluchtstrategie. Jeder ist für sich selbst verantwortlich. Das Management ist nur daran interessiert, dass es eine solche Strategie gibt.
Mit anderen Worten: Jede Person ist gezwungen seine eigene FireEscape()-Methode zu entwickeln. Ein Typ geht über die Feuerleiter hinaus. Ein anderer wird mit dem Fallschirm abspringen. Ein anderer wird mit Hilfe eines Raketenantriebs aus dem Gebäude fliegen. Ein anderer wird sich abseilen. Dem Management ist das egal wie Sie entkommen, sofern Sie einen grundlegenden FireEscape()-Plan haben - wenn nicht, können Sie sicher sein, dass die Arbeitsschutzbehörde die Organisation wie eine Tonne Ziegelsteine angreifen wird. Das ist es, was mit einer abstrakten Methode gemeint ist.
Was ist noch einmal der Unterschied zwischen den beiden?
Abstrakte Methode: Unterklassen sind gezwungen ihre eigene FireEscape-Methode zu implementieren. Mit einer virtuellen Methode haben Sie einen Basisplan zur Verfügung, können aber wählen Ihr eigenes System zu implementieren wenn es nicht gut genug ist.
Das war doch gar nicht so schwer, oder?
Abstrakte Methode: Wenn eine Klasse eine abstrakte Methode enthält, muss diese Klasse als abstrakt deklariert werden. Die abstrakte Methode hat keine Implementierung und daher müssen Klassen, die von dieser abstrakten Klasse abgeleitet sind, eine Implementierung für diese abstrakte Methode bereitstellen.
Virtuelle Methode: Eine Klasse kann eine virtuelle Methode haben. Die virtuelle Methode hat eine Implementierung. Wenn Sie von einer Klasse erben, die eine virtuelle Methode hat, müssen Sie kann die virtuelle Methode außer Kraft setzen und zusätzliche Logik bereitstellen oder die Logik durch Ihre eigene Implementierung ersetzen.
Wann ist was zu verwenden: In manchen Fällen wissen Sie, dass bestimmte Typen eine bestimmte Methode haben sollten, aber Sie wissen nicht, welche Implementierung diese Methode haben sollte.
In solchen Fällen können Sie eine Schnittstelle erstellen, die eine Methode mit dieser Signatur enthält. Wenn Sie jedoch einen solchen Fall haben, aber wissen, dass die Implementierer dieser Schnittstelle auch eine andere gemeinsame Methode haben werden (für die Sie bereits die Implementierung bereitstellen können), können Sie eine abstrakte Klasse erstellen. Diese abstrakte Klasse enthält dann die abstrakte Methode (die überschrieben werden muss) und eine weitere Methode, die die "gemeinsame" Logik enthält.
Eine virtuelle Methode sollte verwendet werden, wenn Sie eine Klasse haben, die direkt verwendet werden kann, für die Sie aber möchten, dass die Erben ein bestimmtes Verhalten ändern können, obwohl dies nicht zwingend erforderlich ist.
Eine abstrakte Methode ist eine Methode, die implementiert werden muss, um eine konkrete Klasse zu bilden. Die Deklaration befindet sich in der abstrakten Klasse (und jede Klasse mit einer abstrakten Methode muss eine abstrakte Klasse sein) und sie muss in einer konkreten Klasse implementiert werden.
Eine virtuelle Methode ist eine Methode, die in einer abgeleiteten Klasse mit dem Override überschrieben werden kann, Ersetzen von das Verhalten in der Oberklasse. Wenn Sie nicht überschreiben, erhalten Sie das ursprüngliche Verhalten. Wenn Sie dies tun, erhalten Sie immer das neue Verhalten. Dies steht im Gegensatz zu nicht virtuellen Methoden, die nicht überschrieben werden können, aber die ursprüngliche Methode verbergen können. Dies geschieht durch die Verwendung der new
Modifikator.
Siehe das folgende Beispiel:
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");
}
}
Wenn ich instanziiere DerivedClass
und rufen SayHello
, oder SayGoodbye
Ich bekomme "Hallo" und "Bis später". Wenn ich anrufe HelloGoodbye
Ich bekomme "Hallo" und "Bis später". Dies ist, weil SayGoodbye
ist virtuell und kann durch abgeleitete Klassen ersetzt werden. SayHello
ist nur versteckt, so dass, wenn ich das von meiner Basisklasse aufrufen ich meine ursprüngliche Methode erhalten.
Abstrakte Methoden sind implizit virtuell. Sie definieren ein Verhalten, das vorhanden sein muss, ähnlich wie eine Schnittstelle es tut.
Ich habe dies vereinfacht, indem ich einige Verbesserungen an den folgenden Klassen (aus anderen Antworten) vorgenommen habe:
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");
}
}
}
Abstrakte Methoden sind immer virtuell. Sie können keine Implementierung haben.
Das ist der Hauptunterschied.
Grundsätzlich würden Sie eine virtuelle Methode verwenden, wenn Sie die "Standard"-Implementierung der Methode haben und Nachkommen erlauben wollen, ihr Verhalten zu ändern.
Mit einer abstrakten Methode zwingen Sie die Nachkommen, eine Implementierung bereitzustellen.