Update: o shared_ptr neste exemplo é como o do Boost, mas não suporta shared_polymorphic_downcast (ou dynamic_pointer_cast ou static_pointer_cast para esse assunto)!
Estou tentando inicializar um ponteiro compartilhado para uma classe derivada sem perder a contagem de referência:
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;
Por enquanto, tudo bem. Eu não esperava que o C ++ convertesse implicitamente Base * em Derivado *. No entanto, eu quero a funcionalidade expressa pelo código (ou seja, manter a contagem de referência enquanto reduz o ponteiro de base). Meu primeiro pensamento foi fornecer um operador de elenco na Base para que uma conversão implícita para Derivado pudesse ocorrer (para pedantes: eu verificaria se o cast para baixo é válido, não se preocupe):
struct Base {
operator Derived* ();
}
// ...
Base::operator Derived* () {
return down_cast<Derived*>(this);
}
Bem, não ajudou. Parece que o compilador ignorou completamente meu operador typecast. Alguma ideia de como eu poderia fazer a atribuição shared_ptr funcionar? Para pontos extras: que tipo de tipo Base* const
é? const Base*
Eu entendo, mas Base* const
? A que se const
refere neste caso?
Respostas:
Você pode usar
dynamic_pointer_cast
. É apoiado porstd::shared_ptr
.Documentação: https://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast
Além disso, não recomendo usar o operador de elenco na classe base. Casting implícito como esse pode se tornar a fonte de bugs e erros.
-Atualizar: Se o tipo não for polimórfico,
std::static_pointer_cast
pode ser usado.fonte
std::shared_ptr
. Mas pelos comentários da primeira resposta eu inferi que ele não está usando boost, então pode estar usandostd::shared_ptr
.Suponho que você esteja usando
boost::shared_ptr
... Acho que você querdynamic_pointer_cast
oushared_polymorphic_downcast
.No entanto, eles requerem tipos polimórficos.
const Base *
é um ponteiro mutável para uma constanteBase
.Base const *
é um ponteiro mutável para uma constanteBase
.Base * const
é um ponteiro constante para um mutávelBase
.Base const * const
é um ponteiro constante para uma constanteBase
.Aqui está um exemplo mínimo:
Não tenho certeza se foi intencional que seu exemplo crie uma instância do tipo base e a projete, mas serve para ilustrar bem a diferença.
A
static_pointer_cast
vontade "apenas faça". Isso resultará em um comportamento indefinido (umDerived*
apontamento para a memória alocada e inicializada porBase
) e provavelmente causará um travamento ou pior. A contagem de referênciabase
será incrementada.O
dynamic_pointer_cast
resultará em um ponteiro nulo. A contagem de referência embase
permanecerá inalterada.O
shared_polymorphic_downcast
terá o mesmo resultado que um elenco estático, mas acionará uma afirmação, em vez de parecer bem-sucedido e levar a um comportamento indefinido. A contagem de referênciabase
será incrementada.Veja (link morto) :
fonte
shared_ptr
construtores (takingstatic_cast_tag
edynamic_cast_tag
), não há muito que você possa fazer. Qualquer coisa que você fizer forashared_ptr
não será capaz de gerenciar o refcount. - Em um design OO "perfeito", você sempre pode usar o tipo base, e nunca precisa saber nem se importar com o que é o tipo derivado, porque toda a sua funcionalidade é exposta por meio de interfaces de classe base. Talvez você só precise repensar por que precisa fazer o down-cast em primeiro lugar.Se alguém chegar aqui com boost :: shared_ptr ...
É assim que você pode fazer o downcast para o Boost derivado shared_ptr. Assumindo que Derived herda da Base.
Certifique-se de que a classe / estrutura 'Base' tenha pelo menos uma função virtual. Um destruidor virtual também funciona.
fonte