Mise à jour: le shared_ptr dans cet exemple est comme celui de Boost, mais il ne prend pas en charge shared_polymorphic_downcast (ou dynamic_pointer_cast ou static_pointer_cast d'ailleurs)!
J'essaye d'initialiser un pointeur partagé vers une classe dérivée sans perdre le nombre de références:
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;
Jusqu'ici tout va bien. Je ne m'attendais pas à ce que C ++ convertisse implicitement Base * en Derived *. Cependant, je veux la fonctionnalité exprimée par le code (c'est-à-dire maintenir le nombre de références tout en abaissant le pointeur de base). Ma première pensée a été de fournir un opérateur de cast dans Base afin qu'une conversion implicite en Derived puisse avoir lieu (pour les pédants: je vérifierais que le down cast est valide, ne vous inquiétez pas):
struct Base {
operator Derived* ();
}
// ...
Base::operator Derived* () {
return down_cast<Derived*>(this);
}
Eh bien, cela n'a pas aidé. Il semble que le compilateur a complètement ignoré mon opérateur de transtypage. Des idées sur la façon dont je pourrais faire fonctionner le devoir shared_ptr? Pour les points supplémentaires: quel type de type Base* const
est-ce? const Base*
Je comprends, mais Base* const
? A quoi fait const
référence dans ce cas?
Réponses:
Vous pouvez utiliser
dynamic_pointer_cast
. Il est soutenu parstd::shared_ptr
.Documentation: https://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast
De plus, je ne recommande pas d'utiliser l'opérateur de cast dans la classe de base. Un casting implicite comme celui-ci peut devenir la source de bogues et d'erreurs.
-Update: Si le type n'est pas polymorphe,
std::static_pointer_cast
peut être utilisé.la source
std::shared_ptr
. Mais d'après les commentaires de la première réponse, j'ai déduit qu'il n'utilisait pas de boost, donc il l'utilisait peut-êtrestd::shared_ptr
.Je suppose que vous utilisez
boost::shared_ptr
... Je pense que vous voulezdynamic_pointer_cast
oushared_polymorphic_downcast
.Cependant, ceux-ci nécessitent des types polymorphes.
const Base *
est un pointeur mutable vers une constanteBase
.Base const *
est un pointeur mutable vers une constanteBase
.Base * const
est un pointeur constant vers un mutableBase
.Base const * const
est un pointeur constant vers une constanteBase
.Voici un exemple minimal:
Je ne sais pas si c'était intentionnel que votre exemple crée une instance du type de base et la jette, mais cela sert à bien illustrer la différence.
La
static_pointer_cast
volonté "faites-le simplement". Cela entraînera un comportement indéfini (unDerived*
pointage sur la mémoire allouée et initialisée parBase
) et causera probablement un plantage, ou pire. Le comptage de référencebase
sera incrémenté.Le
dynamic_pointer_cast
aboutira à un pointeur nul. Le décompte des référencesbase
restera inchangé.Le
shared_polymorphic_downcast
aura le même résultat qu'un cast statique, mais déclenchera une assertion, plutôt que de sembler réussir et de conduire à un comportement indéfini. Le comptage de référencebase
sera incrémenté.Voir (lien mort) :
la source
shared_ptr
constructeurs (prenantstatic_cast_tag
etdynamic_cast_tag
), vous ne pouvez pas faire grand-chose. Tout ce que vous faites à l'extérieurshared_ptr
ne pourra pas gérer le refcount. - Dans une conception OO "parfaite", vous pouvez toujours utiliser le type de base, sans jamais avoir besoin de savoir ni de se soucier de ce qu'est le type dérivé, car toutes ses fonctionnalités sont exposées via des interfaces de classe de base. Peut-être avez-vous juste besoin de repenser la raison pour laquelle vous devez d'abord décliner.Si quelqu'un arrive avec boost :: shared_ptr ...
C'est ainsi que vous pouvez effectuer un downcast vers le Boost dérivé shared_ptr. En supposant que Derived hérite de Base.
Assurez-vous que la classe / structure 'Base' a au moins une fonction virtuelle. Un destructeur virtuel fonctionne également.
la source