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?
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
)
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.
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>
:
Vollständiges Beispiel auf Ideone .
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.
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. :)
Tags und Links c++ casting crtp static-cast upcasting