Oznaczyłeś to trzema językami, a odpowiedzi są bardzo różne w tych trzech. Dyskusja o C ++ mniej lub bardziej implikuje również dyskusję o rzutach C, co daje (mniej więcej) czwartą odpowiedź.
Ponieważ jest to ten, o którym nie wspomniałeś wprost, zacznę od C. Rzuty C mają wiele problemów. Jednym z nich jest to, że mogą robić wiele różnych rzeczy. W niektórych przypadkach rzutowanie nie robi nic poza informacją kompilatora (w zasadzie): „zamknij się, wiem, co robię” - tj. Zapewnia, że nawet gdy wykonujesz konwersję, która może powodować problemy, kompilator nie ostrzeże Cię o tych potencjalnych problemach. Na przykład char a=(char)123456;
. Dokładny wynik tej implementacji zdefiniowany (zależy od rozmiaru i podpisuchar
) iz wyjątkiem dość dziwnych sytuacji, prawdopodobnie nie jest przydatny. Rzuty C różnią się również tym, czy są czymś, co dzieje się tylko w czasie kompilacji (tj. Po prostu mówisz kompilatorowi, jak interpretować / traktować niektóre dane), czy czymś, co dzieje się w czasie wykonywania (np. Rzeczywista konwersja z double do długie).
C ++ próbuje sobie z tym poradzić, przynajmniej do pewnego stopnia, dodając kilka „nowych” operatorów rzutowania, z których każdy jest ograniczony tylko do podzbioru możliwości rzutowania w C. Utrudnia to (na przykład) przypadkowe wykonanie konwersji, której tak naprawdę nie zamierzałeś - jeśli zamierzasz tylko odrzucić stałość na obiekcie, możesz użyć const_cast
i mieć pewność, że jedyną rzeczą, na którą może wpłynąć, jest to, czy celem jest const
, volatile
albo nie. I odwrotnie, a static_cast
nie może wpływać na to, czy obiekt jest const
czyvolatile
. Krótko mówiąc, masz większość tych samych typów możliwości, ale są one podzielone na kategorie, więc jedno rzutowanie może generalnie wykonać tylko jeden rodzaj konwersji, gdzie pojedyncze rzutowanie w stylu C może wykonać dwie lub trzy konwersje w jednej operacji. Podstawowym wyjątkiem jest to, że możesz użyć dynamic_cast
zamiast a static_cast
przynajmniej w niektórych przypadkach i mimo że zostanie zapisane jako a dynamic_cast
, tak naprawdę skończy się jako static_cast
. Na przykład, możesz użyć dynamic_cast
do przechodzenia w górę lub w dół hierarchii klas - ale rzutowanie „w górę” hierarchii jest zawsze bezpieczne, więc można to zrobić statycznie, podczas gdy rzutowanie „w dół” hierarchii niekoniecznie jest bezpieczne, więc wykonywane dynamicznie.
Java i C # są do siebie znacznie bardziej podobne. W szczególności, w przypadku obu z nich rzutowanie jest (praktycznie?) Zawsze operacją wykonywaną. Jeśli chodzi o operatory rzutowania C ++, jest zwykle najbliżej a dynamic_cast
pod względem tego, co naprawdę zostało zrobione - tj. Kiedy próbujesz rzutować obiekt na jakiś typ docelowy, kompilator wstawia sprawdzenie w czasie wykonywania, aby zobaczyć, czy ta konwersja jest dozwolona i zgłoś wyjątek, jeśli tak nie jest. Dokładne szczegóły (np. Nazwa użyta dla wyjątku „złe rzucanie”) są różne, ale podstawowa zasada pozostaje w większości podobna (chociaż, jeśli pamięć służy, Java sprawia, że rzutowania są stosowane do kilku typów niebędących obiektami, takich jak int
znacznie bliższe C rzuty - ale te typy są używane na tyle rzadko, że 1) nie pamiętam tego na pewno i 2) nawet jeśli to prawda, i tak nie ma to większego znaczenia).
Patrząc na rzeczy bardziej ogólnie, sytuacja jest dość prosta (przynajmniej IMO): rzutowanie (oczywiście) oznacza, że konwertujesz coś z jednego typu na inny. Kiedy / jeśli to zrobisz, pojawi się pytanie „Dlaczego?” Jeśli naprawdę chcesz, aby coś było określonym typem, dlaczego nie zdefiniowałeś tego jako tego typu? Nie oznacza to, że nigdy nie ma powodu, aby wykonywać taką konwersję, ale za każdym razem, gdy to nastąpi, powinno nasunąć pytanie, czy można przeprojektować kod, tak aby cały czas był używany prawidłowy typ. Nawet pozornie nieszkodliwe konwersje (np. Między liczbami całkowitymi a zmiennoprzecinkowymi) powinny być zbadane znacznie dokładniej niż jest to powszechne. Pomimo ich pozorupodobieństwo, liczby całkowite powinny być naprawdę używane dla „policzonych” typów rzeczy, a zmiennoprzecinkowe dla „mierzonych” rodzajów rzeczy. Ignorowanie tego rozróżnienia prowadzi do niektórych szalonych stwierdzeń, takich jak „przeciętna amerykańska rodzina ma 1,8 dzieci”. Chociaż wszyscy możemy zobaczyć, jak to się dzieje, faktem jest, że żadna rodzina nie ma 1,8 dzieci. Mogą mieć 1, 2 lub więcej, ale nigdy 1,8.