Wie implementiere ich eine Kompilierzeitprüfung, dass ein Downcast in einem CRTP gültig ist?

8

Ich habe eine einfache alte CRPT (bitte lassen Sie sich nicht von Zugangsbeschränkungen ablenken - die Frage ist nicht über sie):

%Vor%

das ist wie üblich so zu verwenden:

%Vor%

Nun, dass static_cast mich stört. Ich brauche einen Downcast (kein Upcast), also muss ich eine explizite Besetzung verwenden. In allen vernünftigen Fällen wird die Umwandlung gültig sein, da das aktuelle Objekt tatsächlich von der abgeleiteten Klasse ist.

Aber was, wenn ich irgendwie die Hierarchie ändere und der Cast jetzt ungültig wird?

Darf ich irgendwie eine Kompilierzeitprüfung erzwingen, dass in diesem Fall ein expliziter Downcast gültig ist?

    
sharptooth 06.05.2011, 06:41
quelle

5 Antworten

5

Zur Kompilierzeit können Sie nur die statischen Typen überprüfen, und das ist static_cast bereits.

Bei einem Base* ist nur zur Laufzeit bekannt, was sein dynamischer -Typ ist, dh ob er tatsächlich auf ein ConcreteDerived oder etwas verweist sonst. Wenn Sie dies überprüfen möchten, müssen Sie dies zur Laufzeit tun (zum Beispiel mit dynamic_cast )

    
jalf 06.05.2011, 06:47
quelle
4

Für zusätzliche Sicherheit können Sie einen geschützten Konstruktor zu Base hinzufügen, um sicherzustellen, dass etwas daraus abgeleitet wird. Dann wäre das einzige Problem für die wirklich Dummen:

%Vor%

aber das sollte von der ersten Code-Überprüfung oder Testfall abgefangen werden.

    
Bo Persson 06.05.2011 07:07
quelle
3

Um zu erweitern, was @Bo Persson gesagt hat, können Sie eine Kompilierzeitprüfung in besagtem Konstruktor durchführen, zum Beispiel mit Boost.TypeTraits oder C ++ 0x / 11 <type_traits> :

%Vor%

Vollständiges Beispiel auf Ideone .

    
Xeo 06.05.2011 07:27
quelle
2

Es scheint, dass es eine Möglichkeit gibt, die CRPT-Korrektheit zur Kompilierungszeit zu überprüfen.

Wenn wir Base abstract machen (fügen Sie einige reine virtuelle Methoden zu Base hinzu), garantieren wir, dass jede Base-Instanz Teil einer abgeleiteten Instanz ist.

Indem alle Basis-Konstruktoren privat gemacht werden, können wir eine unerwünschte Vererbung von Base verhindern.

Indem wir Abgeleitete als Freund von Base deklarieren, erlauben wir die einzige von CRPT erwartete Vererbung.

Danach sollte CRPT-Downcast korrekt sein (da etwas von der Basis vererbt wird und dieses "Etwas" nur abgeleitet werden kann, nicht irgendeine andere Klasse)

Vielleicht ist der erste Schritt (Base-Abstract machen) aus praktischen Gründen überflüssig, da ein erfolgreicher static_cast garantiert, dass Derived irgendwo in der Base-Hierarchie ist. Dies erlaubt nur einen exotischen Fehler, wenn Abgeleitet von Base <Derived> hergeleitet wird (wie CRPT erwartet), aber gleichzeitig erstellt Abgeleitet eine andere Instanz von Base <derived> (ohne Vererbung) irgendwo im Abgeleiteten Code (es kann, weil es ein Freund ist) . Ich bezweifle jedoch, dass jemand versehentlich so exotischen Code schreiben kann.

    
user396672 28.06.2012 10:22
quelle
1

Wenn Sie etwas wie folgt tun:

%Vor%

Sie können Objekte der class (abgeleitet oder Basis) erstellen. Wenn Sie jedoch versuchen, die Funktion aufzurufen, wird ein Kompilierungsfehler nur für static_cast angezeigt. IMHO wird es alle praktischen Szenarien erfüllen.

Wenn ich die Frage richtig verstanden habe, dann glaube ich, dass die Antwort in Ihrer Frage selbst liegt. :)

    
iammilind 06.05.2011 07:54
quelle