Prüfen, ob Klasse von einer bestimmten Klasse abgeleitet ist (Kompilieren, Laufzeit beide Antworten verfügbar)

8

Es ist einfacher, dies an einem Beispiel zu erklären,

%Vor%

In meiner Bibliothek gibt es einen Zeiger der Basisklasse. Der Benutzer der Bibliothek muss Klassen erstellen, die von basis oder derived1 abgeleitet sind und Zeiger auf diese Klasse zuweisen.

Wie kann ich überprüfen, von welcher Klasse eine benutzerdefinierte Klasse abgeleitet ist?

    
khajvah 07.08.2013, 09:10
quelle

6 Antworten

9

Ich habe einige Anmerkungen zu den vorgeschlagenen x-Laufzeitlösungen für die Kompilierung. Zusätzlich zum Zeitpunkt der Auswertung haben is_base_of und dynamic_cast unterschiedliche Anforderungen und ihre Antworten können unterschiedlich sein.

(1) Um% ce_de% zu verwenden, müssen Basis- und abgeleitete Klassen zuerst polymorph sein (muss mindestens eine dynamic_cast -Methode haben). virtual erfordert nicht, dass die Typen polymorph sind.

(2) Die Operanden von is_base_of sind beide Typen, während is_base_of einen Typ (in dynamic_cast ) und ein Objekt (in < > ) benötigt.

(3) ( ) und dynamic_cast können abhängig vom Vererbungstyp unterschiedliche Antworten geben (oder einer kann kompilieren, während der andere nicht) ( is_base_of vs public oder protected ). Betrachten Sie zum Beispiel:

%Vor%

Wir haben

%Vor%

Tatsächlich ergibt die letzte Zeile einen Compilerfehler in GCC ( private ). VS2010 kompiliert es (ergibt nur eine Warnung ähnlich der GCC-Fehlermeldung).

(4) Die Anforderungen an die Klassen, die polymorph sind, können durch einen Ausnahmebehandlungstrick gelockert werden. Überlegen Sie:

%Vor%

Dann haben wir

%Vor%

Es ist erwähnenswert, dass error: 'B' is an inaccessible base of 'D2' viel langsamer ist als is_unambiguous_public_base_of und (dies wurde nach der Umbenennung, die in der Aktualisierung unten erwähnt wird, deutlicher), gibt immer eine dynamic_cast für Downcasts zurück:

%Vor%

Eine etwas veraltete Referenz zu diesem Trick ist hier .

Haftungsausschluss: Die Implementierung von nullptr oben ist nur ein Entwurf, um den Punkt zu verdeutlichen, und es behandelt nicht korrekt is_unambiguous_public_base_of und const Qualifikationen.

Update : In einer früheren Version dieses Posts wurde volatile is_unambiguous_public_base_of genannt und dies war eine Quelle der Verwirrung. Also habe ich ihn in einen aussagekräftigeren Namen umbenannt. (Danke an Jan Herrmann.)

    
Cassio Neri 07.08.2013, 10:25
quelle
1

Sie könnten dynamic_cast verwenden.

%Vor%     
sashoalm 07.08.2013 09:16
quelle
1
  

Überprüfen Sie, ob die Klasse von einer bestimmten Klasse (Kompilierzeit) abgeleitet ist

Sie können std::is_base_of verwenden:

%Vor%

isBase ist wahr, wenn TheOtherClass von base abgeleitet ist.

    
juanchopanza 07.08.2013 09:14
quelle
1

Ich denke, die Antwort auf diese Frage ist sehr schwierig. Natürlich gibt es std::is_base_of und dynamic_cast . Beide bieten Ihnen einige sehr begrenzte Informationen. Die dritte Option ist das Überladen von Funktionen. Mit all diesen Techniken können Sie einen speziellen Pfad in Ihrem Code auswählen, der ausgeführt werden soll.

std::is_base_of kann in einem booleschen Kontext interpretiert werden und wird entweder von std::true_type oder std::false_type abgeleitet. Diese Tatsache macht es möglich, sie als Parameter für eine Funktion zu verwenden und Kompilierzeit-Polymorphie über Funktionsüberladung zu verwenden. Dieses erste Beispiel zeigt, wie es in einem booleschen Kontext verwendet wird, aber Sie haben keine weiteren spezifischen Typinformationen. Daher wird die Kompilierung in den meisten Fällen fehlschlagen ( siehe hier für eine weitere Beschreibung ) ):

%Vor%

Die zweite Version ist das einfache Überladen von Funktionen. Hier wird der Kompilierzeit-Polymorphismus verwendet, aber alle Informationen des Laufzeittyps gehen verloren (außer virtuelle Funktionen und dynamic_cast werden verwendet):

%Vor%

Jetzt kombiniert die dritte Version beide:

%Vor%

Die dritte Variante wird normalerweise nur für Header-Bibliotheken verwendet, die keinen Laufzeit-Poylmorphismus verwenden (Suche nach std::advance für ein Beispiel).

Jetzt zum Laufzeitpolymorphismus. Hier haben Sie die dynaminc_cast Variante:

%Vor%

Wenn diese Variante nicht schnell genug ist, können Sie Ihren onw-Cast in derived1 implementieren:

%Vor%

Dies ist schnell, aber es skaliert sehr gut für nur sehr wenige (ungefähr 1) abgeleitete Klassen.

Zu guter Letzt sollten Sie über Ihr Klassen-Design nachdenken und überlegen, welche Methoden Sie virtuell machen und in base , derived1 oder anderen Klassen implementieren möchten. Sie sollten unbedingt nach dem Strategie-Pattern suchen.

    
Jan Herrmann 07.08.2013 13:37
quelle
0

Sie können dies auf verschiedene Arten tun. Die häufigsten wie die anderen haben darauf hingewiesen dynamic_cast & lt; & gt; und std::is_base_of . Letzteres wird zur Kompilierungszeit verwendet, während dynamic_cast<> zur Laufzeit verwendet werden kann. HOWEVER , dynamic_cast<> funktioniert nur dann, wenn Ihre Quellklasse polymorph ist (d. h. mindestens eine virtuelle Funktion hat - sie kann eine Methode oder ihr Destruktor sein). Wenn nicht, löst der Compiler einen Fehler aus.

    
Iosif Murariu 07.08.2013 09:24
quelle
0

Der Compiler akzeptiert nur Zeiger auf Klassen, die von Ihrer Basisklasse abgeleitet sind, wenn Ihre Bibliotheksfunktionen Zeiger auf die Basisklasse benötigen. Meine Antwort ist mit einem klassischen Ansatz Typ Sicherheit wird damit umgehen. Nach meiner Erfahrung ist diese Art der Typüberprüfung ausreichend. Mit 25 Jahren Erfahrung in der Branche stelle ich die Notwendigkeit dieser Kontrolle in Frage. Vielleicht ist eine solche grundsätzliche Frage nicht erwünscht? Ich würde gerne die Rechtfertigung sehen, die Notwendigkeit zu haben, diese Art von Upcast durchzuführen. Ich muss das nie tun. Das Gegenteil, d. H. Ein Downcast muss ich ziemlich häufig.

    
Frodo 07.08.2013 09:15
quelle

Tags und Links