Actualización: el shared_ptr en este ejemplo es como el de Boost, pero no es compatible con shared_polymorphic_downcast (o dynamic_pointer_cast o static_pointer_cast para el caso).
Estoy tratando de inicializar un puntero compartido a una clase derivada sin perder el recuento de referencias:
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;
Hasta aquí todo bien. No esperaba que C ++ convirtiera implícitamente Base * a Derived *. Sin embargo, quiero la funcionalidad expresada por el código (es decir, mantener el recuento de referencias mientras se reduce el puntero base). Mi primer pensamiento fue proporcionar un operador de conversión en Base para que pudiera tener lugar una conversión implícita a Derivado (para los pedantes: comprobaría que la conversión hacia abajo es válida, no se preocupe):
struct Base {
operator Derived* ();
}
// ...
Base::operator Derived* () {
return down_cast<Derived*>(this);
}
Bueno, no ayudó. Parece que el compilador ignoró completamente mi operador encasillado. ¿Alguna idea de cómo podría hacer que funcione la asignación shared_ptr? Para puntos extra: ¿qué tipo Base* constes? const Base*Entiendo, pero Base* const? ¿A qué se constrefiere en este caso?

Respuestas:
Puede utilizar
dynamic_pointer_cast. Es apoyado porstd::shared_ptr.Documentación: https://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast
Además, no recomiendo usar el operador de conversión en la clase base. La transmisión implícita como esta puede convertirse en la fuente de errores y errores.
-Actualización: si el tipo no es polimórfico,
std::static_pointer_castse puede utilizar.fuente
std::shared_ptr. Pero de los comentarios de la primera respuesta deduje que no está usando boost, por lo que puede estar usandostd::shared_ptr.Supongo que estás usando
boost::shared_ptr... Creo que quieresdynamic_pointer_castoshared_polymorphic_downcast.Sin embargo, estos requieren tipos polimórficos.
const Base *es un puntero mutable a una constanteBase.Base const *es un puntero mutable a una constanteBase.Base * constes un puntero constante a un mutableBase.Base const * constes un puntero constante a una constanteBase.Aquí tienes un ejemplo mínimo:
No estoy seguro de si fue intencional que su ejemplo creara una instancia del tipo base y la lanzara, pero sirve para ilustrar la diferencia muy bien.
La
static_pointer_castvoluntad "simplemente hazlo". Esto dará como resultado un comportamiento indefinido (unDerived*apuntar a la memoria asignada e inicializada porBase) y probablemente causará un bloqueo, o algo peor. Sebaseincrementará el recuento de referencias .El
dynamic_pointer_castresultará en un puntero nulo. El recuento de referenciasbaseno se modificará.El
shared_polymorphic_downcasttendrá el mismo resultado que un molde estático, sino que desencadenará una afirmación, más que aparente tener éxito y que conduce a un comportamiento indefinido. Sebaseincrementará el recuento de referencias .Ver (enlace muerto) :
fuente
shared_ptrconstructores (tomandostatic_cast_tagydynamic_cast_tag), no hay mucho que pueda hacer. Cualquier cosa que hagas fuerashared_ptrno podrá gestionar el recuento. - En un diseño OO "perfecto" siempre se puede utilizar el tipo base, y nunca necesitará saber ni preocuparse cuál es el tipo derivado, porque toda su funcionalidad se expone a través de interfaces de clase base. Quizás solo necesites repensar por qué necesitas rebajar en primer lugar.Si alguien llega aquí con boost :: shared_ptr ...
Así es como puede bajar al Boost shared_ptr derivado. Suponiendo que Derived hereda de Base.
Asegúrese de que la clase / estructura 'Base' tenga al menos una función virtual. Un destructor virtual también funciona.
fuente