Aktualizacja: shared_ptr w tym przykładzie jest podobne do tego w Boost, ale nie obsługuje shared_polymorphic_downcast (ani dynamic_pointer_cast lub static_pointer_cast w tym przypadku)!
Próbuję zainicjować udostępniony wskaźnik do klasy pochodnej bez utraty liczby odwołań:
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;
Na razie w porządku. Nie spodziewałem się, że C ++ niejawnie przekonwertuje Base * na Derived *. Jednak chcę, aby funkcjonalność wyrażona w kodzie (czyli utrzymanie liczby odwołań podczas obniżania wskaźnika podstawowego). Moją pierwszą myślą było zapewnienie operatora rzutowania w Base, aby mogła mieć miejsce niejawna konwersja do Derived (dla pedantów: sprawdziłbym, czy rzutowanie w dół jest prawidłowe, nie martw się):
struct Base {
operator Derived* ();
}
// ...
Base::operator Derived* () {
return down_cast<Derived*>(this);
}
Cóż, to nie pomogło. Wygląda na to, że kompilator całkowicie zignorował mój operator typecast. Jakieś pomysły, jak mogę sprawić, by przypisanie shared_ptr działało? Za dodatkowe punkty: jaki to rodzaj Base* const
? const Base*
Rozumiem, ale Base* const
? Do czego to się const
odnosi w tym przypadku?
Odpowiedzi:
Możesz użyć
dynamic_pointer_cast
. Jest obsługiwany przezstd::shared_ptr
.Dokumentacja: https://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast
Nie polecam też używania operatora rzutowania w klasie bazowej. Niejawne rzutowanie, takie jak to, może stać się źródłem błędów i błędów.
-Aktualizacja: jeśli typ nie jest polimorficzny,
std::static_pointer_cast
można użyć.źródło
std::shared_ptr
. Ale z komentarzy do pierwszej odpowiedzi wywnioskowałem, że nie używa doładowania, więc może używastd::shared_ptr
.Zakładam, że używasz
boost::shared_ptr
... Myślę, że chceszdynamic_pointer_cast
lubshared_polymorphic_downcast
.Jednak wymagają one typów polimorficznych.
const Base *
jest zmiennym wskaźnikiem do stałejBase
.Base const *
jest zmiennym wskaźnikiem do stałejBase
.Base * const
jest stałym wskaźnikiem do mutableBase
.Base const * const
jest stałym wskaźnikiem do stałejBase
.Oto minimalny przykład:
Nie jestem pewien, czy to było zamierzone, aby Twój przykład tworzył instancję typu podstawowego i rzucał ją, ale służy to ładnemu zilustrowaniu różnicy.
static_pointer_cast
Wola „po prostu zrób to”. Spowoduje to niezdefiniowane zachowanie (Derived*
wskazanie na pamięć przydzieloną i zainicjowaną przezBase
) i prawdopodobnie spowoduje awarię lub gorzej. Licznik odwołańbase
zostanie zwiększony.dynamic_pointer_cast
Spowoduje wskaźnik NULL. Liczymy na referencjebase
pozostanie niezmieniony.shared_polymorphic_downcast
Będzie miał taki sam wynik jak gipsie statycznym, ale wywoła twierdzenie, niż zdaje się uda i prowadzi do nieokreślonego zachowania. Licznik odwołańbase
zostanie zwiększony.Zobacz (martwy link) :
źródło
shared_ptr
konstruktorów (biorącstatic_cast_tag
idynamic_cast_tag
), niewiele można zrobić. Cokolwiek zrobisz na zewnątrzshared_ptr
, nie będzie w stanie zarządzać zwrotem. - W „doskonałym” projekcie obiektowym można zawsze używać typu podstawowego i nigdy nie trzeba wiedzieć, ani obchodzić się z typem pochodnym, ponieważ cała jego funkcjonalność jest ujawniana przez interfejsy klasy bazowej. Być może po prostu musisz ponownie przemyśleć, dlaczego musisz rzucić w dół.Jeśli ktoś dotrze tutaj z boost :: shared_ptr ...
W ten sposób możesz obniżyć do pochodnego Boost shared_ptr. Zakładając, że Derived dziedziczy po Base.
Upewnij się, że klasa / struktura „Base” ma co najmniej jedną funkcję wirtualną. Działa również wirtualny destruktor.
źródło