Frage Müssen ALLE virtuellen Funktionen in abgeleiteten Klassen implementiert werden?


Das mag wie eine einfache Frage erscheinen, aber ich kann die Antwort nirgendwo anders finden.

Angenommen, ich habe Folgendes:

class Abstract {
public:
    virtual void foo() = 0;
    virtual void bar();
}

class Derived : Abstract {
public:
    virtual void foo();
}

Ist es in Ordnung, dass die Klasse Derived die Funktion bar () nicht implementiert? Was, wenn nicht alle meine abgeleiteten Klassen die Funktion bar () benötigen, aber einige tun. Müssen alle virtuellen Funktionen einer abstrakten Basisklasse in die abgeleiteten Klassen implementiert werden, oder nur diejenigen, die rein virtuell sind? Vielen Dank


75
2018-01-19 18:51


Ursprung


Antworten:


Abgeleitete Klassen tun dies nicht muss implementieren alle virtuelle Funktionen selbst. Sie müssen nur das implementieren rein Einsen.1 Das bedeutet die Derived Klasse in der Frage ist richtig. Es erbt das bar Implementierung von seiner Vorgängerklasse, Abstract. (Dies setzt voraus, dass Abstract::bar ist irgendwo implementiert. Der Code in der Frage deklariert die Methode, definiert sie jedoch nicht. Sie können es inline als definieren Trenkis Antwort zeigt, oder Sie können es separat definieren.)


1 Und selbst dann nur, wenn die abgeleitete Klasse sein wird instanziiert. Wenn eine abgeleitete Klasse nicht direkt instanziiert wird, sondern nur als eine Basisklasse von mehr abgeleiteten Klassen existiert, dann ist es das jene Klassen, die dafür verantwortlich sind, dass alle ihre rein virtuellen Methoden implementiert sind. Die "mittlere" Klasse in der Hierarchie darf einige rein virtuelle Methoden nicht implementiert haben, genau wie die Basisklasse. Wenn die "mittlere" Klasse tut Wenn Sie eine reine virtuelle Methode implementieren, übernehmen deren Nachkommen diese Implementierung, sodass sie sie nicht erneut implementieren müssen.


64
2018-01-19 18:52



Nur die reinen virtuellen Methoden müssen in abgeleiteten Klassen implementiert werden, aber Sie benötigen immer noch eine Definition (und nicht nur eine Deklaration) der anderen virtuellen Methoden. Wenn Sie keinen liefern, könnte sich der Linker sehr beschweren.

Also, einfach Putten {} nachdem Ihre optionale virtuelle Methode Ihnen eine leere Standardimplementierung zur Verfügung stellt:

class Abstract {
public:
    virtual void foo() = 0; // pure virtual must be overridden
    virtual void bar() {}   // virtual with empty default implementation
};

class Derived : Abstract {
public:
    virtual void foo();
};

Eine komplexere Standardimplementierung würde jedoch in eine separate Quelldatei gehen.


33
2018-01-19 19:00



Der ISO C ++ Standard gibt an, dass alle virtuellen Methoden einer Klasse, die nicht rein virtuell sind, definiert werden müssen.

Einfach gesagt ist die Regel:
Wenn Ihre abgeleitete Klasse die virtuelle Methode Base-Klasse überschreibt, sollte sie auch eine Definition bereitstellen. Wenn nicht, dann sollte die Base-Klasse die Definition dieser Methode bereitstellen.

Gemäß der obigen Regel in Ihrem Codebeispiel virtual void bar(); benötigt eine Definition in der Basisklasse.

Referenz:

C ++ 03 Standard: 10.3 Virtuelle Funktionen [class.virtual] 

Eine virtuelle Funktion, die in einer Klasse deklariert ist, muss in dieser Klasse definiert oder als rein (10.4) deklariert sein oder beides; aber keine Diagnose ist erforderlich (3.2).

Entweder sollten Sie die Funktion rein virtuell machen oder eine Definition dafür bereitstellen.

Das gcc faq dokumentiert es auch:

Der ISO C ++ Standard gibt an, dass alle virtuellen Methoden einer Klasse, die nicht rein virtuell sind, definiert sein müssen, aber keine Diagnose für Verletzungen dieser Regel erfordert [class.virtual]/8. Basierend auf dieser Annahme gibt GCC nur die implizit definierten Konstruktoren, den Zuweisungsoperator, den Destruktor und die virtuelle Tabelle einer Klasse in der Übersetzungseinheit aus, die ihre erste derartige nicht-inline-Methode definiert.

Wenn Sie diese bestimmte Methode nicht definieren, kann der Linker daher über das Fehlen von Definitionen für scheinbar nicht verwandte Symbole beschweren. Um diese Fehlermeldung zu verbessern, ist es leider möglicherweise erforderlich, den Linker zu ändern, was nicht immer möglich ist.

Die Lösung besteht darin, sicherzustellen, dass alle virtuellen Methoden, die nicht rein sind, definiert sind. Beachten Sie, dass ein Destruktor auch dann definiert sein muss, wenn er als rein virtuell deklariert ist [class.dtor]/7.


7
2018-01-19 19:10



Ja, das ist in Ordnung ... Sie müssen nur reine virtuelle Funktionen implementieren, um eine aus einer abstrakten Basisklasse abgeleitete Klasse zu instanziieren.


3
2018-01-19 18:52



Ja, es ist richtig, dass eine abgeleitete Klasse die Funktion, die Pure Virtual in der Elternklasse ist, ÜBERSCHREITEN muss. Elternklasse mit einer reinen virtuellen Funktion wird nur als abstrakte Klasse bezeichnet, weil ihre Kindklasse ihren eigenen Körper der reinen virtuellen Funktion angeben muss.

Für die normalen virtuellen Funktionen: - Es ist nicht notwendig, sie weiter zu überschreiben, da einige untergeordnete Klassen diese Funktion haben können, andere nicht.

Der Hauptzweck des Virtual Function Mechanismus ist der Run Time Polymorphism, egal ob der Hauptzweck der Pure Virtual Function (Abstrakte Klasse) es ist, den gleichen Namen Function mit dem eigenen Körper zu haben.


0
2018-01-19 19:36