Antworten:
Aus der virtuellen Funktion von Wikipedia ...
Bei der objektorientierten Programmierung in Sprachen wie C ++ und Object Pascal ist eine virtuelle Funktion oder virtuelle Methode eine vererbbare und überschreibbare Funktion oder Methode, für die der dynamische Versand erleichtert wird. Dieses Konzept ist ein wichtiger Bestandteil des (Laufzeit-) Polymorphismus-Teils der objektorientierten Programmierung (OOP). Kurz gesagt, eine virtuelle Funktion definiert eine auszuführende Zielfunktion, aber das Ziel ist zur Kompilierungszeit möglicherweise nicht bekannt.
Im Gegensatz zu einer nicht virtuellen Funktion wird beim Überschreiben einer virtuellen Funktion die am meisten abgeleitete Version auf allen Ebenen der Klassenhierarchie verwendet und nicht nur auf der Ebene, auf der sie erstellt wurde. Wenn daher eine Methode der Basisklasse eine virtuelle Methode aufruft , wird die in der abgeleiteten Klasse definierte Version anstelle der in der Basisklasse definierten Version verwendet.
Dies steht im Gegensatz zu nicht virtuellen Funktionen, die in einer abgeleiteten Klasse weiterhin überschrieben werden können. Die "neue" Version wird jedoch nur von der abgeleiteten Klasse und darunter verwendet, ändert jedoch die Funktionalität der Basisklasse überhaupt nicht.
wohingegen..
Eine rein virtuelle Funktion oder eine rein virtuelle Methode ist eine virtuelle Funktion, die von einer abgeleiteten Klasse implementiert werden muss, wenn die abgeleitete Klasse nicht abstrakt ist.
Wenn eine rein virtuelle Methode vorhanden ist, ist die Klasse "abstrakt" und kann nicht alleine instanziiert werden. Stattdessen muss eine abgeleitete Klasse verwendet werden, die die rein virtuellen Methoden implementiert. Eine reine virtuelle wird überhaupt nicht in der Basisklasse definiert sind , so dass eine abgeleitete Klasse muss es bestimmen, oder dass abgeleitete Klasse ist auch abstrakt und nicht instanziiert werden kann. Nur eine Klasse ohne abstrakte Methoden kann instanziiert werden.
Eine virtuelle bietet eine Möglichkeit, die Funktionalität der Basisklasse zu überschreiben, und eine reine virtuelle erfordert dies.
pure
Schlüsselwort hinzufügen wollte , aber dass Bell Labs im Begriff war, eine Hauptversion von C ++ zu veröffentlichen, und sein Manager würde dies zu diesem späten Zeitpunkt nicht zulassen. Das Hinzufügen von Schlüsselwörtern ist eine große Sache.
Ich möchte die Wikipedia-Definition von virtuell kommentieren, die hier von mehreren wiederholt wird. [Zum Zeitpunkt der Erstellung dieser Antwort] definierte Wikipedia eine virtuelle Methode als eine Methode, die in Unterklassen überschrieben werden kann. [Glücklicherweise wurde Wikipedia seitdem bearbeitet und erklärt dies nun korrekt.] Das ist falsch: Jede Methode, nicht nur virtuelle, kann in Unterklassen überschrieben werden. Virtual bietet Ihnen Polymorphismus, dh die Möglichkeit, zur Laufzeit die am häufigsten abgeleitete Überschreibung einer Methode auszuwählen .
Betrachten Sie den folgenden Code:
#include <iostream>
using namespace std;
class Base {
public:
void NonVirtual() {
cout << "Base NonVirtual called.\n";
}
virtual void Virtual() {
cout << "Base Virtual called.\n";
}
};
class Derived : public Base {
public:
void NonVirtual() {
cout << "Derived NonVirtual called.\n";
}
void Virtual() {
cout << "Derived Virtual called.\n";
}
};
int main() {
Base* bBase = new Base();
Base* bDerived = new Derived();
bBase->NonVirtual();
bBase->Virtual();
bDerived->NonVirtual();
bDerived->Virtual();
}
Was ist die Ausgabe dieses Programms?
Base NonVirtual called.
Base Virtual called.
Base NonVirtual called.
Derived Virtual called.
Abgeleitet überschreibt jede Methode von Base: nicht nur die virtuelle, sondern auch die nicht virtuelle.
Wir sehen, dass, wenn Sie einen Basiszeiger auf abgeleitet haben (bDerived), der Aufruf von NonVirtual die Implementierung der Basisklasse aufruft. Dies wird zur Kompilierungszeit behoben: Der Compiler erkennt, dass bDerived eine Basis * ist, dass NonVirtual nicht virtuell ist, und führt daher die Auflösung auf Basis der Klasse Base durch.
Beim Aufrufen von Virtual wird jedoch die Implementierung der abgeleiteten Klasse aufgerufen. Aufgrund des Schlüsselworts virtual erfolgt die Auswahl der Methode zur Laufzeit und nicht zur Kompilierungszeit. Was hier zur Kompilierungszeit passiert, ist, dass der Compiler erkennt, dass dies eine Base * ist und dass er eine virtuelle Methode aufruft, sodass er anstelle der Klasse Base einen Aufruf an die vtable einfügt. Diese vtable wird zur Laufzeit instanziiert, daher die Laufzeitauflösung für die am meisten abgeleitete Überschreibung.
Ich hoffe das war nicht zu verwirrend. Kurz gesagt, jede Methode kann überschrieben werden, aber nur virtuelle Methoden bieten Polymorphismus, dh Laufzeitauswahl der am meisten abgeleiteten Überschreibung. In der Praxis wird das Überschreiben einer nicht virtuellen Methode jedoch als schlechte Praxis angesehen und nur selten verwendet. Daher denken viele Leute (einschließlich derjenigen, die diesen Wikipedia-Artikel geschrieben haben), dass nur virtuelle Methoden überschrieben werden können.
Derived*
mit denselben Funktionsaufrufen hinzuzufügen , um den Punkt nach Hause zu fahren. Ansonsten tolle Antwort
Das virtuelle Schlüsselwort gibt C ++ die Möglichkeit, Polymorphismus zu unterstützen. Wenn Sie einen Zeiger auf ein Objekt einer Klasse haben, z.
class Animal
{
public:
virtual int GetNumberOfLegs() = 0;
};
class Duck : public Animal
{
public:
int GetNumberOfLegs() { return 2; }
};
class Horse : public Animal
{
public:
int GetNumberOfLegs() { return 4; }
};
void SomeFunction(Animal * pAnimal)
{
cout << pAnimal->GetNumberOfLegs();
}
In diesem (albernen) Beispiel gibt die Funktion GetNumberOfLegs () die entsprechende Nummer zurück, die auf der Klasse des Objekts basiert, für das sie aufgerufen wird.
Betrachten Sie nun die Funktion 'SomeFunction'. Es ist egal, welche Art von Tierobjekt an es übergeben wird, solange es von Animal abgeleitet ist. Der Compiler wandelt jede von Tieren abgeleitete Klasse automatisch in ein Tier um, da es sich um eine Basisklasse handelt.
Wenn wir das tun:
Duck d;
SomeFunction(&d);
es würde '2' ausgeben. Wenn wir das tun:
Horse h;
SomeFunction(&h);
es würde '4' ausgeben. Das können wir nicht machen:
Animal a;
SomeFunction(&a);
weil es nicht kompiliert werden kann, weil die virtuelle Funktion GetNumberOfLegs () rein ist, was bedeutet, dass es durch Ableiten von Klassen (Unterklassen) implementiert werden muss.
Reine virtuelle Funktionen werden hauptsächlich verwendet, um Folgendes zu definieren:
a) abstrakte Klassen
Dies sind Basisklassen, von denen Sie ableiten und dann die reinen virtuellen Funktionen implementieren müssen.
b) Schnittstellen
Dies sind 'leere' Klassen, in denen alle Funktionen rein virtuell sind und Sie daher alle Funktionen ableiten und dann implementieren müssen.
In einer C ++ - Klasse ist virtual das Schlüsselwort, das angibt, dass eine Methode von einer Unterklasse überschrieben (dh implementiert) werden kann. Zum Beispiel:
class Shape
{
public:
Shape();
virtual ~Shape();
std::string getName() // not overridable
{
return m_name;
}
void setName( const std::string& name ) // not overridable
{
m_name = name;
}
protected:
virtual void initShape() // overridable
{
setName("Generic Shape");
}
private:
std::string m_name;
};
In diesem Fall kann eine Unterklasse die initShape- Funktion überschreiben , um spezielle Arbeiten auszuführen :
class Square : public Shape
{
public:
Square();
virtual ~Square();
protected:
virtual void initShape() // override the Shape::initShape function
{
setName("Square");
}
}
Der Begriff " rein virtuell" bezieht sich auf virtuelle Funktionen, die von einer Unterklasse implementiert werden müssen und von der Basisklasse nicht implementiert wurden. Sie legen eine Methode als rein virtuell fest, indem Sie das Schlüsselwort virtual verwenden und am Ende der Methodendeklaration a = 0 hinzufügen .
Wenn Sie Shape :: initShape rein virtuell machen möchten, gehen Sie wie folgt vor:
class Shape
{
...
virtual void initShape() = 0; // pure virtual method
...
};
Indem Sie Ihrer Klasse eine rein virtuelle Methode hinzufügen, machen Sie die Klasse zu einer abstrakten Basisklasse, die sehr praktisch ist, um Schnittstellen von der Implementierung zu trennen.
m_name
. Was bedeutet das m_
?
"Virtuell" bedeutet, dass die Methode in Unterklassen überschrieben werden kann, jedoch eine direkt aufrufbare Implementierung in der Basisklasse hat. "Rein virtuell" bedeutet, dass es sich um eine virtuelle Methode ohne direkt aufrufbare Implementierung handelt. Eine solche Methode muss mindestens einmal in der Vererbungshierarchie überschrieben werden. Wenn eine Klasse über nicht implementierte virtuelle Methoden verfügt, können Objekte dieser Klasse nicht erstellt werden und die Kompilierung schlägt fehl.
@quark weist darauf hin, dass rein virtuelle Methoden kann eine Implementierung, sondern als reine virtuelle Methoden außer Kraft gesetzt werden muss, kann die Standardimplementierung nicht direkt aufgerufen werden. Hier ist ein Beispiel für eine rein virtuelle Methode mit einer Standardeinstellung:
#include <cstdio>
class A {
public:
virtual void Hello() = 0;
};
void A::Hello() {
printf("A::Hello\n");
}
class B : public A {
public:
void Hello() {
printf("B::Hello\n");
A::Hello();
}
};
int main() {
/* Prints:
B::Hello
A::Hello
*/
B b;
b.Hello();
return 0;
}
Laut Kommentaren ist es compilerspezifisch, ob die Kompilierung fehlschlägt oder nicht. Zumindest in GCC 4.3.3 wird es nicht kompiliert:
class A {
public:
virtual void Hello() = 0;
};
int main()
{
A a;
return 0;
}
Ausgabe:
$ g++ -c virt.cpp
virt.cpp: In function ‘int main()’:
virt.cpp:8: error: cannot declare variable ‘a’ to be of abstract type ‘A’
virt.cpp:1: note: because the following virtual functions are pure within ‘A’:
virt.cpp:3: note: virtual void A::Hello()
Wie funktioniert das virtuelle Schlüsselwort?
Angenommen, der Mensch ist eine Basisklasse, der Inder ist vom Menschen abgeleitet.
Class Man
{
public:
virtual void do_work()
{}
}
Class Indian : public Man
{
public:
void do_work()
{}
}
Das Deklarieren von do_work () als virtuell bedeutet einfach: Welches do_work () aufgerufen werden soll, wird NUR zur Laufzeit bestimmt.
Angenommen, ich tue,
Man *man;
man = new Indian();
man->do_work(); // Indian's do work is only called.
Wenn virtual nicht verwendet wird, wird dies vom Compiler statisch bestimmt oder statisch gebunden, je nachdem, welches Objekt aufgerufen wird. Wenn also ein Objekt des Menschen do_work () aufruft, heißt das do_work () des Menschen AUCH, obwohl es auf ein indisches Objekt verweist
Ich glaube, dass die am häufigsten gewählte Antwort irreführend ist - Jede Methode, ob virtuell oder nicht, kann eine überschriebene Implementierung in der abgeleiteten Klasse haben. Unter besonderer Bezugnahme auf C ++ ist der korrekte Unterschied die Laufzeitbindung (wenn virtuell verwendet wird) und die Kompilierungszeit (wenn virtuell nicht verwendet wird, aber eine Methode überschrieben wird und ein Basiszeiger auf ein abgeleitetes Objekt zeigt) Bindung der zugehörigen Funktionen.
Es scheint einen weiteren irreführenden Kommentar zu geben, der besagt:
"Justin, 'pure virtual' ist nur ein Begriff (kein Schlüsselwort, siehe meine Antwort unten), der bedeutet:" Diese Funktion kann von der Basisklasse nicht implementiert werden. "
DAS IST FALSCH! Rein virtuelle Funktionen können auch einen Körper haben UND IMPLEMENTIERT WERDEN! Die Wahrheit ist, dass die reine virtuelle Funktion einer abstrakten Klasse statisch aufgerufen werden kann! Zwei sehr gute Autoren sind Bjarne Stroustrup und Stan Lippman ... weil sie die Sprache geschrieben haben.
Eine virtuelle Funktion ist eine Mitgliedsfunktion, die in einer Basisklasse deklariert und von einer abgeleiteten Klasse neu definiert wird. Virtuelle Funktionen sind in der Reihenfolge ihrer Vererbung hierarchisch. Wenn eine abgeleitete Klasse eine virtuelle Funktion nicht überschreibt, wird die in ihrer Basisklasse definierte Funktion verwendet.
Eine reine virtuelle Funktion enthält keine Definition in Bezug auf die Basisklasse. Es hat keine Implementierung in der Basisklasse. Jede abgeleitete Klasse muss diese Funktion überschreiben.
In Simula, C ++ und C #, die standardmäßig statische Methodenbindungen verwenden, kann der Programmierer festlegen, dass bestimmte Methoden dynamische Bindungen verwenden sollen, indem sie sie als virtuell kennzeichnen. Die dynamische Methodenbindung ist für die objektorientierte Programmierung von zentraler Bedeutung.
Objektorientierte Programmierung erfordert drei grundlegende Konzepte: Kapselung, Vererbung und dynamische Methodenbindung.
Durch die Kapselung können die Implementierungsdetails einer Abstraktion hinter einer einfachen Schnittstelle verborgen werden.
Durch Vererbung kann eine neue Abstraktion als Erweiterung oder Verfeinerung einer vorhandenen Abstraktion definiert werden, wobei einige oder alle ihrer Merkmale automatisch erhalten werden.
Durch die dynamische Methodenbindung kann die neue Abstraktion ihr neues Verhalten auch dann anzeigen, wenn sie in einem Kontext verwendet wird, der die alte Abstraktion erwartet.
Virtuelle Methoden können durch Ableiten von Klassen überschrieben werden, benötigen jedoch eine Implementierung in der Basisklasse (die überschrieben wird).
Reine virtuelle Methoden haben keine Implementierung der Basisklasse. Sie müssen durch abgeleitete Klassen definiert werden. (Technisch überschrieben ist also nicht der richtige Begriff, da es nichts zu überschreiben gibt).
Virtual entspricht dem Standardverhalten von Java, wenn die abgeleitete Klasse eine Methode der Basisklasse überschreibt.
Reine virtuelle Methoden entsprechen dem Verhalten abstrakter Methoden innerhalb abstrakter Klassen. Und eine Klasse, die nur reine virtuelle Methoden und Konstanten enthält, wäre das cpp-Pendant zu einer Schnittstelle.
Reine virtuelle Funktion
Versuchen Sie diesen Code
#include <iostream>
using namespace std;
class aClassWithPureVirtualFunction
{
public:
virtual void sayHellow()=0;
};
class anotherClass:aClassWithPureVirtualFunction
{
public:
void sayHellow()
{
cout<<"hellow World";
}
};
int main()
{
//aClassWithPureVirtualFunction virtualObject;
/*
This not possible to create object of a class that contain pure virtual function
*/
anotherClass object;
object.sayHellow();
}
Entfernen Sie in der Klasse anotherClass die Funktion sayHellow und führen Sie den Code aus. Sie erhalten eine Fehlermeldung! Wenn eine Klasse eine reine virtuelle Funktion enthält, kann kein Objekt aus dieser Klasse erstellt werden und es wird geerbt, dann muss ihre abgeleitete Klasse diese Funktion implementieren.
Virtuelle Funktion
versuchen Sie es mit einem anderen Code
#include <iostream>
using namespace std;
class aClassWithPureVirtualFunction
{
public:
virtual void sayHellow()
{
cout<<"from base\n";
}
};
class anotherClass:public aClassWithPureVirtualFunction
{
public:
void sayHellow()
{
cout<<"from derived \n";
}
};
int main()
{
aClassWithPureVirtualFunction *baseObject=new aClassWithPureVirtualFunction;
baseObject->sayHellow();///call base one
baseObject=new anotherClass;
baseObject->sayHellow();////call the derived one!
}
Hier wird die Funktion sayHellow in der Basisklasse als virtuell markiert. Dies ist der Compiler, der versucht, die Funktion in der abgeleiteten Klasse zu durchsuchen und die Funktion zu implementieren. Wenn sie nicht gefunden wird, führen Sie die Basisfunktion aus. Danke
"Eine virtuelle Funktion oder virtuelle Methode ist eine Funktion oder Methode, deren Verhalten innerhalb einer ererbenden Klasse von einer Funktion mit derselben Signatur überschrieben werden kann" - Wikipedia
Dies ist keine gute Erklärung für virtuelle Funktionen. Denn selbst wenn ein Mitglied nicht virtuell ist, kann das Erben von Klassen es überschreiben. Sie können versuchen, es selbst zu sehen.
Der Unterschied zeigt sich, wenn eine Funktion eine Basisklasse als Parameter verwendet. Wenn Sie eine erbende Klasse als Eingabe angeben, verwendet diese Funktion die Basisklassenimplementierung der Überschreibungsfunktion. Wenn diese Funktion jedoch virtuell ist, wird die in der Ableitungsklasse implementierte verwendet.
Virtuelle Funktionen müssen eine Definition in der Basisklasse und auch in der abgeleiteten Klasse haben, sind jedoch nicht erforderlich. Beispielsweise ist die Funktion ToString () oder toString () eine virtuelle Funktion, sodass Sie Ihre eigene Implementierung bereitstellen können, indem Sie sie in benutzerdefinierten Klassen überschreiben.
Virtuelle Funktionen werden in der normalen Klasse deklariert und definiert.
Die reine virtuelle Funktion muss mit "= 0" deklariert werden und kann nur in der abstrakten Klasse deklariert werden.
Eine abstrakte Klasse mit einer reinen virtuellen Funktion (en) kann keine Definition (en) dieser reinen virtuellen Funktionen haben. Dies bedeutet, dass die Implementierung in Klassen bereitgestellt werden muss, die von dieser abstrakten Klasse abgeleitet sind.