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* const
es? const Base*
Entiendo, pero Base* const
? ¿A qué se const
refiere 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_cast
se 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_cast
oshared_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 * const
es un puntero constante a un mutableBase
.Base const * const
es 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_cast
voluntad "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. Sebase
incrementará el recuento de referencias .El
dynamic_pointer_cast
resultará en un puntero nulo. El recuento de referenciasbase
no se modificará.El
shared_polymorphic_downcast
tendrá 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. Sebase
incrementará el recuento de referencias .Ver (enlace muerto) :
fuente
shared_ptr
constructores (tomandostatic_cast_tag
ydynamic_cast_tag
), no hay mucho que pueda hacer. Cualquier cosa que hagas fuerashared_ptr
no 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