Update: Das shared_ptr in diesem Beispiel ähnelt dem in Boost, unterstützt jedoch nicht shared_polymorphic_downcast (oder dynamic_pointer_cast oder static_pointer_cast)!
Ich versuche, einen gemeinsam genutzten Zeiger auf eine abgeleitete Klasse zu initialisieren, ohne den Referenzzähler zu verlieren:
struct Base { };
struct Derived : public Base { };
shared_ptr<Base> base(new Base());
shared_ptr<Derived> derived;
// error: invalid conversion from 'Base* const' to 'Derived*'
derived = base;
So weit, ist es gut. Ich hatte nicht erwartet, dass C ++ Base * implizit in Derived * konvertiert. Ich möchte jedoch, dass die Funktionalität durch den Code ausgedrückt wird (dh die Referenzanzahl wird beibehalten, während der Basiszeiger heruntergespielt wird). Mein erster Gedanke war, einen Cast-Operator in Base bereitzustellen, damit eine implizite Konvertierung in Derived stattfinden kann (für Pedanten: Ich würde überprüfen, ob der Down-Cast gültig ist, keine Sorge):
struct Base {
operator Derived* ();
}
// ...
Base::operator Derived* () {
return down_cast<Derived*>(this);
}
Nun, es hat nicht geholfen. Es scheint, dass der Compiler meinen Typecast-Operator völlig ignoriert hat. Irgendwelche Ideen, wie ich die shared_ptr-Zuweisung zum Laufen bringen könnte? Für zusätzliche Punkte: Was für ein Typ Base* const
ist das? const Base*
Ich verstehe, aber Base* const
? Worauf bezieht const
sich in diesem Fall?
Antworten:
Sie können verwenden
dynamic_pointer_cast
. Es wird unterstützt vonstd::shared_ptr
.Dokumentation: https://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast
Außerdem empfehle ich nicht, den Cast-Operator in der Basisklasse zu verwenden. Implizites Casting wie dieses kann zur Quelle von Fehlern und Fehlern werden.
-Update: Wenn der Typ nicht polymorph ist,
std::static_pointer_cast
kann verwendet werden.quelle
std::shared_ptr
. Aber aus den Kommentaren der ersten Antwort schloss ich, dass er keinen Boost verwendet, also verwendet er möglicherweisestd::shared_ptr
.Ich nehme an, Sie verwenden
boost::shared_ptr
... Ich denke, Sie wollendynamic_pointer_cast
odershared_polymorphic_downcast
.Diese erfordern jedoch polymorphe Typen.
const Base *
ist ein veränderlicher Zeiger auf eine KonstanteBase
.Base const *
ist ein veränderlicher Zeiger auf eine KonstanteBase
.Base * const
ist ein konstanter Zeiger auf eine veränderbareBase
.Base const * const
ist ein konstanter Zeiger auf eine KonstanteBase
.Hier ist ein minimales Beispiel:
Ich bin nicht sicher, ob es beabsichtigt war, dass Ihr Beispiel eine Instanz des Basistyps erstellt und umwandelt, aber es dient dazu, den Unterschied gut zu veranschaulichen.
Der
static_pointer_cast
Wille "mach es einfach". Dies führt zu undefiniertem Verhalten (einDerived*
Hinweis auf den Speicher, der zugewiesen und von initialisiert wurdeBase
) und führt wahrscheinlich zu einem Absturz oder schlimmerem. Der Referenzzählerbase
wird erhöht.Das
dynamic_pointer_cast
führt zu einem Nullzeiger. Die Referenzanzahlbase
bleibt unverändert.Das
shared_polymorphic_downcast
Ergebnis hat das gleiche Ergebnis wie eine statische Besetzung, löst jedoch eine Behauptung aus, anstatt erfolgreich zu sein und zu undefiniertem Verhalten zu führen. Der Referenzzählerbase
wird erhöht.Siehe (toter Link) :
quelle
shared_ptr
Konstruktoren (takestatic_cast_tag
unddynamic_cast_tag
) zu implementieren , können Sie nicht viel tun. Alles, was Sie draußen tunshared_ptr
, kann die Nachzählung nicht verwalten. - In einem "perfekten" OO-Design können Sie immer den Basistyp verwenden und müssen nie wissen oder sich darum kümmern, was der abgeleitete Typ ist, da seine gesamte Funktionalität über Schnittstellen der Basisklasse verfügbar gemacht wird. Vielleicht müssen Sie nur überlegen, warum Sie überhaupt runterwerfen müssen.Wenn jemand mit boost :: shared_ptr hierher kommt ...
Auf diese Weise können Sie auf den abgeleiteten Boost shared_ptr herunterstufen. Angenommen, Abgeleitet erbt von Base.
Stellen Sie sicher, dass die Basisklasse / Struktur mindestens eine virtuelle Funktion hat. Ein virtueller Destruktor funktioniert ebenfalls.
quelle