c++ - Downcasting shared_ptr<Base> a shared_ptr<Derivado>?
gcc boost (3)
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).
Intento 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 ++ implícitamente convirtiera Base * en Derived *. Sin embargo, sí quiero la funcionalidad expresada por el código (es decir, mantener el recuento de referencias mientras se baja el puntero base). Mi primer pensamiento fue proporcionar un operador de reparto en Base para que pudiera tener lugar una conversión implícita a Derived (para pedantes: comprobaría que el lanzamiento descendente es válido, no se preocupe):
struct Base {
operator Derived* ();
}
// ...
Base::operator Derived* () {
return down_cast<Derived*>(this);
}
Bueno, no ayudó. Parece que el compilador ignoró por completo a mi operador de typecast. ¿Alguna idea de cómo podría hacer que la asignación shared_ptr funcione? Para puntos extra: ¿qué tipo de tipo Base* const
es? const Base*
Lo entiendo, pero Base* const
? ¿A qué se refiere const
en este caso?
Puede usar dynamic_pointer_cast
. Es compatible con std::shared_ptr
.
std::shared_ptr<Base> base (new Derived());
std::shared_ptr<Derived> derived =
std::dynamic_pointer_cast<Derived> (base);
Además, no recomiendo usar el operador de reparto en la clase base. La conversión implícita como esta puede convertirse en la fuente de errores y errores.
-Update: si el tipo no es polimórfico, se puede usar std::static_pointer_cast
.
Supongo que estás utilizando boost::shared_ptr
... Creo que quieres dynamic_pointer_cast
o shared_polymorphic_downcast
.
Sin embargo, estos requieren tipos polimórficos.
¿Qué tipo de tipo
Base* const
es?const Base*
Lo entiendo, peroBase* const
? ¿A qué se refiereconst
en este caso?
-
const Base *
es un puntero mutable a unaBase
constante. -
Base const *
es un puntero mutable a unaBase
constante. -
Base * const
es un puntero constante a unaBase
mutable. -
Base const * const
es un puntero constante a unaBase
constante.
Aquí hay un ejemplo mínimo:
struct Base { virtual ~Base() { } }; // dynamic casts require polymorphic types
struct Derived : public Base { };
boost::shared_ptr<Base> base(new Base());
boost::shared_ptr<Derived> derived;
derived = boost::static_pointer_cast<Derived>(base);
derived = boost::dynamic_pointer_cast<Derived>(base);
derived = boost::shared_polymorphic_downcast<Derived>(base);
No estoy seguro si fue intencional que tu ejemplo crea una instancia del tipo base y lo lanza, pero sirve para ilustrar la diferencia muy bien.
El static_pointer_cast
"simplemente lo hará". Esto dará como resultado un comportamiento indefinido (un Derived*
apuntando a la memoria asignada e inicializada por Base
) y probablemente causará un bloqueo, o algo peor. El recuento de referencia en la base
se incrementará.
El dynamic_pointer_cast
dará como resultado un puntero nulo. El recuento de referencias en la base
cambiará.
shared_polymorphic_downcast
tendrá el mismo resultado que un lanzamiento estático, pero activará una afirmación, en lugar de tener éxito y conducir a un comportamiento indefinido. El recuento de referencia en la base
se incrementará.
Ver (enlace muerto) :
A veces es un poco difícil decidir si usar
static_cast
odynamic_cast
, y desearía poder tener un poco de ambos mundos. Es bien sabido que dynamic_cast tiene una sobrecarga de tiempo de ejecución, pero es más seguro, mientras que static_cast no tiene ninguna sobrecarga, pero puede fallar silenciosamente. Qué bueno sería si pudiera usarshared_dynamic_cast
en las compilaciones de depuración yshared_static_cast
en las compilaciones de lanzamiento. Bueno, tal cosa ya está disponible y se llamashared_polymorphic_downcast
.
Si alguien llega aquí con boost :: shared_ptr ...
Esta es la forma en que puede bajar a Boost shared_ptr derivado. Suponiendo que Derived hereda de Base.
boost::shared_ptr<Base> bS;
bS.reset(new Derived());
boost::shared_ptr<Derived> dS = boost::dynamic_pointer_cast<Derived,Base>(bS);
std::cout << "DerivedSPtr is: " << std::boolalpha << (dS.get() != 0) << std::endl;
Asegúrese de que la clase / estructura ''Base'' tenga al menos una función virtual. Un destructor virtual también funciona.