Ich habe gehört, dass Vorlagen für C ++ - Klassenmitgliedsfunktionen nicht virtuell sein können. Ist das wahr?
Wenn sie virtuell sein können, was ist ein Beispiel für ein Szenario, in dem man eine solche Funktion verwenden würde?
c++
templates
virtual-functions
function-templates
c++-faq
WannaBeGeek
quelle
quelle
Antworten:
In Vorlagen dreht sich alles um den Compiler, der zur Kompilierungszeit Code generiert . Bei virtuellen Funktionen dreht sich alles um das Laufzeitsystem, um herauszufinden, welche Funktion zur Laufzeit aufgerufen werden soll .
Sobald das Laufzeitsystem herausgefunden hat, dass es eine virtuelle Funktion mit Vorlagen aufrufen muss, ist die Kompilierung abgeschlossen und der Compiler kann die entsprechende Instanz nicht mehr generieren. Daher können Sie keine Funktionsvorlagen für virtuelle Elemente haben.
Es gibt jedoch einige leistungsstarke und interessante Techniken, die sich aus der Kombination von Polymorphismus und Vorlagen ergeben, insbesondere die sogenannte Typlöschung .
quelle
Virtual functions are all about the run-time system figuring out which function to call at run-time
- Entschuldigung, aber das ist ein ziemlich falscher Weg und ziemlich verwirrend. Es ist nur eine Indirektion, und es ist keine "Laufzeitermittlung" beteiligt. Während der Kompilierungszeit ist bekannt, dass die aufzurufende Funktion diejenige ist, auf die der n-te Zeiger in der vtable zeigt. "Herausfinden" impliziert, dass es Typprüfungen und dergleichen gibt, was nicht der Fall ist.Once the run-time system figured out it would need to call a templatized virtual function
- Ob die Funktion virtuell ist oder nicht, ist zur Kompilierungszeit bekannt.void f(concr_base& cb, virt_base& vb) { cb.f(); vb.f(); }
, "weiß" er, welche Funktion an demcb.f()
aufgerufenen Punkt aufgerufen wird, und weiß das nicht fürvb.f()
. Letztere muss herausgefunden, zur Laufzeit , durch das Laufzeitsystem . Ob Sie dies als "Herausfinden" bezeichnen möchten und ob dies mehr oder weniger effizient ist, ändert nichts an diesen Fakten.Aus C ++ - Vorlagen Das vollständige Handbuch:
quelle
C ++ erlaubt derzeit keine Funktionen für virtuelle Vorlagenmitglieder. Der wahrscheinlichste Grund ist die Komplexität der Implementierung. Rajendra gibt einen guten Grund an, warum dies derzeit nicht möglich ist, aber es könnte mit vernünftigen Änderungen des Standards möglich sein. Insbesondere wenn Sie den Ort des virtuellen Funktionsaufrufs berücksichtigen, ist es schwierig, herauszufinden, wie viele Instanziierungen einer Vorlagenfunktion tatsächlich vorhanden sind, und die vtable aufzubauen. Standard-Leute haben gerade eine Menge anderer Dinge zu tun und C ++ 1x ist auch für die Compiler-Autoren eine Menge Arbeit.
Wann würden Sie eine Vorlagenelementfunktion benötigen? Ich bin einmal auf eine solche Situation gestoßen, in der ich versucht habe, eine Hierarchie mit einer reinen virtuellen Basisklasse umzugestalten. Es war ein schlechter Stil für die Umsetzung verschiedener Strategien. Ich wollte das Argument einer der virtuellen Funktionen in einen numerischen Typ ändern und anstatt die Elementfunktion zu überladen und jede Überladung in allen Unterklassen zu überschreiben, habe ich versucht, virtuelle Vorlagenfunktionen zu verwenden (und musste herausfinden, dass sie nicht existieren .)
quelle
Virtuelle Funktionstabellen
Beginnen wir mit einigen Hintergrundinformationen zu virtuellen Funktionstabellen und ihrer Funktionsweise ( Quelle ):
Mein Problem oder wie ich hierher gekommen bin
Ich versuche jetzt, so etwas für eine Cubefile-Basisklasse mit vorlagenoptimierten Ladefunktionen zu verwenden, die für verschiedene Arten von Cubes unterschiedlich implementiert werden (einige nach Pixel, andere nach Bild usw.).
Etwas Code:
Was ich gerne hätte, aber es wird aufgrund einer Kombination aus virtuellen Vorlagen nicht kompiliert:
Am Ende habe ich die Vorlagendeklaration auf die Klassenebene verschoben. Diese Lösung hätte Programme gezwungen, bestimmte Datentypen zu kennen, die sie lesen würden, bevor sie sie lesen, was nicht akzeptabel ist.Lösung
Warnung, das ist nicht sehr hübsch, aber es hat mir erlaubt, sich wiederholenden Ausführungscode zu entfernen
1) in der Basisklasse
2) und in den Kinderklassen
Beachten Sie, dass LoadAnyCube in der Basisklasse nicht deklariert ist.
Hier ist eine weitere Antwort zum Stapelüberlauf mit einer Problemumgehung: Sie benötigen eine Problemumgehung für virtuelle Vorlagenmitglieder .
quelle
Der folgende Code kann mit MinGW G ++ 3.4.5 unter Windows 7 kompiliert und ordnungsgemäß ausgeführt werden:
und die Ausgabe ist:
Und später habe ich eine neue Klasse X hinzugefügt:
Als ich versuchte, Klasse X in main () wie folgt zu verwenden:
g ++ meldet den folgenden Fehler:
Es ist also offensichtlich, dass:
quelle
Nein, können sie nicht. Aber:
hat fast den gleichen Effekt, wenn Sie nur eine gemeinsame Schnittstelle haben und die Implementierung auf Unterklassen verschieben möchten.
quelle
Foo
Zeiger ist qualifiziert alsFoo<Bar>
, er kann nicht auf einFoo<Barf>
oder zeigenFoo<XXX>
.Nein, Vorlagenelementfunktionen können nicht virtuell sein.
quelle
In den anderen Antworten ist die vorgeschlagene Vorlagenfunktion eine Fassade und bietet keinen praktischen Nutzen.
Die Sprache erlaubt keine virtuellen Vorlagenfunktionen, aber mit einer Problemumgehung ist es möglich, beide zu haben, z. B. eine Vorlagenimplementierung für jede Klasse und eine virtuelle gemeinsame Schnittstelle.
Es ist jedoch erforderlich, für jede Kombination von Vorlagentypen eine virtuelle Dummy-Wrapper-Funktion zu definieren:
Ausgabe:
Probieren Sie es hier aus
quelle
Um den zweiten Teil der Frage zu beantworten:
Dies ist keine unvernünftige Sache. Zum Beispiel hat Java (wo jede Methode virtuell ist) keine Probleme mit generischen Methoden.
Ein Beispiel in C ++ für den Wunsch nach einer virtuellen Funktionsvorlage ist eine Elementfunktion, die einen generischen Iterator akzeptiert. Oder eine Mitgliedsfunktion, die ein generisches Funktionsobjekt akzeptiert.
Die Lösung für dieses Problem besteht darin, die Typlöschung mit der Funktion boost :: any_range und boost :: zu verwenden, mit der Sie einen generischen Iterator oder Funktor akzeptieren können, ohne Ihre Funktion zu einer Vorlage machen zu müssen.
quelle
Es gibt eine Problemumgehung für die 'virtuelle Vorlagenmethode', wenn eine Reihe von Typen für die Vorlagenmethode im Voraus bekannt ist.
Um die Idee zu zeigen, werden im folgenden Beispiel nur zwei Typen verwendet (
int
unddouble
).Dort
Base::Method
ruft eine 'virtuelle' Vorlagenmethode ( ) die entsprechende virtuelle Methode (eine vonBase::VMethod
) auf, die wiederum die Implementierung der Vorlagenmethode ( ) aufruftImpl::TMethod
.Man muss nur die Template-Methode
TMethod
in abgeleiteten Implementierungen (AImpl
,BImpl
) implementieren und verwendenDerived<*Impl>
.Ausgabe:
NB:
Base::Method
ist tatsächlich ein Überschuss für echten Code (VMethod
kann veröffentlicht und direkt verwendet werden). Ich habe es hinzugefügt, damit es wie eine tatsächliche "virtuelle" Vorlagenmethode aussieht.quelle
Base
Klasse jedes Mal ändern müssen, wenn Sie eine Vorlagenfunktion mit einem Argumenttyp aufrufen müssen, der nicht mit den bisher implementierten kompatibel ist. Diese Notwendigkeit zu vermeiden ist die Absicht von Vorlagen ...Während eine ältere Frage, die von vielen beantwortet wurde, meiner Meinung nach eine prägnante Methode ist, die sich nicht so stark von den anderen unterscheidet, ist die Verwendung eines kleinen Makros, um das Duplizieren von Klassendeklarationen zu erleichtern.
Um nun unsere Unterklasse zu implementieren:
Der Vorteil hierbei ist, dass beim Hinzufügen eines neu unterstützten Typs alles über den abstrakten Header erfolgen kann und möglicherweise nicht in mehreren Quell- / Header-Dateien korrigiert werden kann.
quelle
Zumindest mit gcc 5.4 könnten virtuelle Funktionen Vorlagenmitglieder sein, müssen aber selbst Vorlagen sein.
Ausgänge
quelle
Versuche dies:
Schreiben Sie in classeder.h:
Überprüfen Sie, ob Sie damit arbeiten, um diesen Code in main.cpp zu schreiben:
quelle