___ qstnhdr ___ Verwirrung über statischen CRTP-Polymorphismus
___ antwort43821770 ___
Die Sache ist, dass die Beschreibung von CRTP als "statischer Polymorphismus" nicht wirklich hilfreich oder genau ist, was CRPT betrifft. Beim Polymorphismus geht es eigentlich nur um verschiedene Typen, die dieselbe Schnittstelle oder denselben Vertrag erfüllen; Wie diese verschiedenen Typen diese Schnittstelle implementieren, ist orthogonal zum Polymorphismus. Der dynamische Polymorphismus sieht so aus:
%Vor%
Dabei ist d.algorithm
eine Basisklasse, die eine virtuelle Base
-Methode bereitstellt, die Derived
, Base
usw. überschreibt. Hier ist der statische Polymorphismus:
%Vor%
Und das ist es. Sie können die statische Version von Derived
für jeden Typ aufrufen, der eine Derived
-Methode definiert, ohne von einer Basisklasse zu erben. Und der Anruf wird zur Kompilierungszeit aufgelöst (d. H. Sie zahlen nicht für einen Vtable-Anruf).
Wo passt CRTP? Bei CRTP geht es wirklich nicht um die Schnittstelle, es geht also nicht um Polymorphie. Bei CRTP geht es darum, dass Sie Dinge einfacher implementieren können. Was CRTP magisch macht, ist, dass es Dinge direkt in die Schnittstelle eines Typs injizieren kann, mit vollem Wissen über alles, was der abgeleitete Typ bietet. Ein einfaches Beispiel könnte sein:
%Vor%
Nun kann jeder Klasse, die einen Additionsoperator definiert, auch eine Base
-Methode zugewiesen werden:
%Vor%
Bei CRTP dreht sich alles um die Unterstützung bei der Implementierung, nicht um die Schnittstelle. Also nicht zu lange darüber auf, dass es oft als "statische Polymorphie" bezeichnet wird. Wenn Sie das echte kanonische Beispiel für die Verwendung von CRTP benötigen, sollten Sie Kapitel 1 von Andrei Alexandrescus Modern C ++ - Design in Betracht ziehen. Aber, nehmen Sie es langsam: -).
___ tag123c ___ C ++ ist eine universelle Programmiersprache. Es wurde ursprünglich als Erweiterung von C entworfen und behält eine ähnliche Syntax, ist aber jetzt eine komplett andere Sprache. Verwenden Sie dieses Tag für Fragen zu Code, der mit einem C ++ - Compiler kompiliert werden soll.
___ antwort43821627 ___
Die Vorteile von CRTP werden erst deutlich, wenn mehr als eine Funktion involviert ist. Betrachten Sie diesen Code (ohne CRTP):
%Vor%
Dies gibt aus:
0
[Live-Beispiel]
Aufgrund der statischen Natur des C ++ - Typsystems ruft der Aufruf von static_sub_func
alle Funktionen von Derived::static_sub_func
auf. Die versuchten Überschreibungen in virtual
werden nicht aufgerufen.
Dies ändert sich, wenn CRTP verwendet wird:
%Vor%
Ausgabe:
Wir sind fertig!
-26
[Live-Beispiel]
Auf diese Weise wird die Implementierung in Derived
tatsächlich in %code% aufgerufen, wenn %code% eine "Überschreibung" bereitstellt.
Dies wäre sogar in Ihrem ursprünglichen Code sichtbar: Wenn %code% keine CRTP-Klasse ist, wird der Aufruf von %code% niemals in %code% aufgelöst.
Was die Vorteile von CRTP gegenüber anderen Ansätzen sind:
-
CRTP versus %code% Funktionen:
CRTP ist ein Kompilierzeitkonstrukt, dh es ist kein Laufzeitaufwand verbunden. Das Aufrufen einer virtuellen Funktion über eine Basisklassenreferenz (normalerweise) erfordert einen Aufruf über einen Zeiger zur Funktion und somit indirekte Kosten und verhindert das Inlining.
-
CRTP versus einfach alles in %code% implementieren:
Wiederverwendung der Basisklassencodes.
Natürlich ist CRTP ein rein kompilierbares Konstrukt. Um den kompilierbaren Polymorphismus zu erreichen, müssen Sie ein kompilierbares polymorphes Konstrukt verwenden: Templates. Es gibt zwei Möglichkeiten, dies zu tun:
%Vor%
Ersteres entspricht näher dem Laufzeit-Polymorphismus und bietet eine bessere Typensicherheit, letzteres ist mehr auf Duck-Typ basiert.
___ qstntxt ___
Ich versuche meinen Kopf um das CRTP zu wickeln. Es gibt einige gute Quellen, einschließlich dieses Forums, aber ich denke, ich habe etwas Verwirrung über die Grundlagen des statischen Polymorphismus. Blick auf den folgenden Wikipedia-Eintrag:
%Vor%
Ich verstehe, dass dies mir hilft, verschiedene implementation () - Varianten in abgeleiteten Klassen zu haben, ähnlich einer virtuellen Kompilierungsfunktion. Meine Verwirrung ist jedoch, dass ich glaube, dass ich keine Funktionen wie
haben kann
%Vor%
wie bei normaler Vererbung und virtuellen Funktionen, da Base als Template verwendet wird, aber ich müsste
angeben
%Vor%
oder verwenden
%Vor%
Also, was kauft mir CRTP in diesem Zusammenhang, anstatt einfach die Methode in Derived :: Base zu überschatten / zu implementieren?
%Vor%
___ tag123crtp ___ Das seltsam wiederkehrende Vorlagenmuster (CRTP) ist ein C ++ - Idiom, in dem eine Klasse X von einer Klassenvorlageninstanziierung abgeleitet wird, wobei X selbst als Vorlagenargument verwendet wird.
___ answer44187495 ___
Sie haben Recht, dass weder
%Vor%
oder
%Vor%
gibt Ihnen statischen Polymorphismus. Die erste kompiliert nicht, weil %code% kein Typ und die zweite nicht polymorph ist.
Angenommen, Sie haben zwei abgeleitete Klassen, %code% und %code% . Dann können Sie %code% selbst zu einer Vorlage machen.
%Vor%
Dies kann dann mit jedem Typ aufgerufen werden, der von %code% abgeleitet ist, und es wird der statische Typ des übergebenen Parameters verwendet, um zu entscheiden, welche Funktion aufgerufen werden soll.
Dies ist nur eine der Anwendungen von CRTP, und wenn ich raten würde, würde ich das weniger häufige sagen. Sie können es auch als Nir Friedman in einer anderen Antwort verwenden, die nichts mit statischem Polymorphismus zu tun hat. p>
Beide Anwendungen werden sehr gut diskutiert hier
___