W języku C++ rzutowanie typów pozwala wyraźnie wskazać kompilatorowi, jak przekształcić obiekt z jednego typu na inny. W wcześniejszych wersjach C++ (C++98) używano do tego rzutowania w stylu C ((int)x). Jednak takie podejście jest niejawne i często prowadzi do błędów, ponieważ kompilator nie może kontrolować poprawności lub bezpieczeństwa przekształcenia. W celu zwiększenia bezpieczeństwa wprowadzono wyspecjalizowane operatory rzutowania typów, wśród których static_cast odgrywa ważną rolę.
Historia pytania:
Przed wprowadzeniem słowa kluczowego static_cast, programiści często napotykali błędy spowodowane niejawymi przekształceniami. Dzięki wprowadzeniu static_cast w C++98 stało się możliwe wyraźne rozróżnienie różnych zamiarów i gwarancja, że rzutowanie odbywa się tylko tam, gdzie jest to logiczne na etapie kompilacji.
Problem:
Często zachodzi potrzeba przekształcania kompatybilnych typów (na przykład wartości numeryczne lub wskaźniki na klasy powiązane dziedziczeniem), ale robić to w sposób przejrzysty i bezpieczny. Standardowe rzutowanie w stylu C niejawnie miesza sprawdzane przez kompilator i potencjalnie niebezpieczne przekształcenia.
Rozwiązanie:
static_cast jest przeznaczone do wyraźnego, ale statycznie sprawdzanego rzutowania kompatybilnych typów. Jest bezpieczniejsze niż zwykłe rzutowanie w stylu C i nie pozwala na rzutowanie całkowicie niekompatybilnych typów na etapie kompilacji.
Przykład kodu:
class Base { }; class Derived : public Base { }; Base* b = new Derived(); Derived* d1 = static_cast<Derived*>(b); // poprawnie, jeśli b faktycznie wskazuje na Derived int x = 10; double y = static_cast<double>(x); // działa
Kluczowe cechy:
dynamic_cast)Czy można używać static_cast do przekształcania między całkowicie niepowiązanymi typami, na przykład int i double**
Nie, kompilator nie pozwoli wykonać takiego rzutowania bez wyraźnego pośredniego przekształcenia przez void*, ponieważ typy nie są bezpośrednio powiązane. Na przykład:
int* p1; double* p2 = static_cast<double*>(p1); // błąd kompilacji
Czy można używać static_cast do bezpiecznego "zaniżającego" rzutowania z klasy bazowej na pochodną? Co się stanie, jeśli wskaźnik nie wskazuje na obiekt typu pochodnego?
static_cast może wykonać takie rzutowanie, ale nie sprawdza rzeczywistego typu w czasie wykonywania. Jeśli wskaźnik bazowy nie wskazuje na obiekt potrzebnej klasy pochodnej, wynik będzie nieokreślonym zachowaniem:
Base* base = new Base; Derived* wrong = static_cast<Derived*>(base); // UB! Typ nie ten
Jak static_cast zachowuje się z prywatnym dziedziczeniem?
static_cast nie pozwoli na przekształcenie wskaźnika lub referencji z klasy bazowej na pochodną poprzez prywatne lub chronione dziedziczenie poza klasą dziedziczącą lub jej przyjaciółmi — wystąpi błąd czasu kompilacji.
Programista bezmyślnie używa static_cast do przekształcania dowolnego wskaźnika na klasę bazową w pochodną, nie sprawdzając rzeczywistego podległego typu (na przykład dla przyspieszenia wydajności).
Zalety:
Wady:
Użycie static_cast tylko po sprawdzeniu typu obiektu przy pomocy dodatkowych metadanych lub projektowania (lub do bezpiecznych przekształceń typów numerycznych).
Zalety:
Wady: