rzutowania w stylu c lub rzutowania w stylu c ++

21

Więc czego używasz?

int anInt = (int)aFloat;

lub

int anInt = static_cast<int>(aFloat);
// and its brethren

A co ważniejsze, dlaczego?

bastibe
źródło

Odpowiedzi:

45

Po pierwsze, zrozum, że te linie nie są równoważne .

int* anInt = (int*)aFloat; // is equivalent to

int* anInt = reinterpret_cast<int*>(aFloat); 

To, co się tutaj dzieje, polega na tym, że programista prosi kompilator o zrobienie wszystkiego, co w jego mocy, aby wykonać rzutowanie.

Różnica jest ważna, ponieważ użycie static_cast poprosi tylko o typ podstawowy, który jest „bezpieczny” do przekonwertowania, gdzie reinterpret_cast przekonwertuje na cokolwiek, być może po prostu odwzorowując pożądany układ pamięci na pamięć danego obiektu.

Ponieważ „filtr” nie jest taki sam, używanie konkretnej rzutowania jest bardziej przejrzyste i bezpieczne niż używanie rzutowania C, jeśli polegasz na kompilatorze (lub w środowisku wykonawczym, jeśli używasz dynamicznej wersji), aby powiedzieć ci, gdzie zrobiłeś coś złego , unikając przesyłania C i reinterepret_cast.

Teraz, gdy jest to bardziej jasne, jest jeszcze jedna rzecz: static_cast, reinterpret_cast, const_cast i dynamic_cast są łatwiejsze do wyszukiwania .

I najważniejszy punkt: są brzydkie . To jest pożądane. Potencjalnie błędny kod, zapach kodu, oczywiste „sztuczki”, które mogą generować błędy, są łatwiejsze do wyśledzenia, gdy wiąże się to z brzydkim wyglądem. Zły kod powinien być brzydki .

To „zgodnie z projektem”. Dzięki temu programiści wiedzą, gdzie mógłby zrobić coś lepiej (całkowicie unikając rzutów, jeśli nie jest to naprawdę potrzebne) i gdzie jest w porządku, ale jest to „udokumentowane” w kodzie przez „oznaczenie” go jako brzydkiego.

Drugim powodem wprowadzenia obsady w nowym stylu było to, że obsady w stylu C są bardzo trudne do wykrycia w programie. Na przykład nie można wygodnie wyszukiwać rzutów za pomocą zwykłego edytora lub edytora tekstu. Ta niemal niewidoczność rzutów w stylu C jest szczególnie niefortunna, ponieważ są one potencjalnie szkodliwe. Brzydka operacja powinna mieć brzydką składniową formę. Ta obserwacja była jednym z powodów wyboru składni w obsadach w nowym stylu. Kolejnym powodem było dopasowanie rzutowań w nowym stylu do zapisu szablonu, aby programiści mogli pisać własne rzutowania, zwłaszcza rzutowania sprawdzone w czasie wykonywania.

Może dlatego, że static_cast jest tak brzydki i stosunkowo trudny do napisania, prawdopodobnie częściej pomyślisz dwa razy, zanim go użyjesz? Byłoby dobrze, ponieważ rzutów naprawdę można w większości uniknąć w nowoczesnym C ++.

Źródło: Bjarne Stroustrup (twórca C ++)

Klaim
źródło
2
Głosowałbym za tym, gdybym miał jeszcze kilka punktów, ale niestety nie mogę. Rzuty w stylu c NIE są równoważne z reinterpretacją_castu. Zastanów się reinterpret_cast<int>(double);. Jest całkowicie możliwe rzutowanie podwójnego na int za pomocą rzutowania w stylu c, ale nie można tego zrobić za pomocą reinterpret_cast. Widzę, że Timbo już ci to wskazał, i powiedziałeś, że to naprawisz, ale cztery lata później pozostaje to niepoprawne. Chciałbym jednak nadal głosować, jeśli to zostało naprawione, ponieważ istnieją całkowicie uzasadnione powody, aby użyć obsady. Oto lepsza odpowiedź: stackoverflow.com/a/332086/3878168
Yay295
36

Rzutowania w C ++ są bardziej restrykcyjne (więc lepiej wyrażaj swoje zamiary i ułatwiaj przeglądanie kodu itp.). Są również znacznie łatwiejsze do wyszukiwania, jeśli zajdzie taka potrzeba.

Bruce Stephens
źródło
10
... i są bardziej skłonni do robienia tego, co zamierzasz. ;-)
Macke
7
I są o wiele więcej do pisania, co daje jeszcze jeden powód, aby poprawiać typy bez potrzeby rzucania.
Michael Kohne
7
I są brzydkie jako funkcja, dzięki czemu oczywiste jest, gdzie w kodzie mogą występować punkty usprawnienia lub specjalne przypadki, które mogą wymagać dokumentacji. - edytuj: wow Właśnie odkryłem, że również odpowiedziałem na to pytanie! XD
Klaim
Dlaczego miałbym ich szukać?
Deduplicator
@Deduplicator Istnieje wiele powodów, dla których warto wiedzieć, gdzie odbywają się rzutowania w bazie kodu. Na przykład podczas wyłapywania błędów, które mogą być związane z przesyłaniem (w szczególności podczas programowania międzyplatformowego).
Klaim
13

Opcja C: rzutowanie w stylu „C ++”, ponieważ nie można go odróżnić od konstrukcji:

int anInt = int(aFloat);

lub nawet:

int anInt(aFloat);

Poza tym, poza tymi trywialnymi przypadkami z prymitywami, które są dobrze zrozumiane, wolę używać x_cast <> nad rzutami w stylu C. Istnieją trzy powody, dla których:

  • Zawężają one definicję operacji, którą programista próbował wykonać.

  • Mogą wykonywać działania, których nie można użyć w stylu C (szczególnie w przypadku dynamicznego rzutowania <>, które mogą rzutować krzyżowo na gałęzie łańcucha wielokrotnego dziedziczenia).

  • brzydkie . Głośno deklarują, że programista działa przeciwko systemowi typów. W tym przypadku to dobra rzecz.

Kaz Dragon
źródło
7

Jeśli piszesz kod w C, użyj rzutowania C. Jeśli piszesz w C ++, użyj rzutowania w C ++.

Podczas gdy większość rzutowań narusza odpowiednie bezpieczeństwo typu, C ++ są bardziej restrykcyjne, a zatem jesteś nieco mniej niebezpieczny pod względem typu niż w przypadku rzutowania C.

Mogę tolerować osobę używającą (T *) NULL, aby wymusić przeciążenie ...

Dojną krową
źródło
7

Mam kilka zasad dotyczących rzutów w stylu C / C ++:

  1. Wyłączenie stałej musi zawsze używać const_cast. Z oczywistych powodów. Niestety, moja reguła o nie stosowaniu stałej powodującej, że klawiatura podnosi się i łamie palec programisty, nie została zatwierdzona.
  2. Każdy shenanigans w stylu manipulacji bitami, do którego programiści podchodzą, schodząc do metalu, powinien użyć reinterpret_cast. Jest to naprawdę rzut, którego nie ma C: udawaj, że bity tej liczby całkowitej są w rzeczywistości bitami float. Pozwala to uniknąć takich nieprzyjemności (int)(*(int*)(&floatVar)).
  3. Jeśli wpiszesz słowa „ dynamic_cast”, zatrzymaj i ponownie oceń swoją polimorficzną hierarchię klas i projekt. Kontynuuj ponowną ocenę projektu hierarchii klas, aż będziesz mógł usunąć te słowa.
  4. Nie przejmuj się static_cast.

Powodem # 4 jest po prostu to, że to nie ma znaczenia. Okoliczności, które nie pasują do innych zasad, są albo oczywiste, albo naprawdę niskie. Dobrze zrozumiana konwersja prostych typów, takich jak int-to-float, nie powinna wymagać specjalnej składni. A jeśli jesteś w głębi, brzydkie wnętrzności czegoś, cóż, jesteś w głębi, brzydkie wnętrzności czegoś. Nie trzeba zwracać uwagi na fakt, że „tutaj są smoki”, ponieważ zęby, pazury i ogień już to dawały.

Nicol Bolas
źródło
1
dynamic_castjest doskonale ważnym narzędziem. Przyznaję, że rzadko przydatny, ale daleko mu do szatana takich rzeczy jak zmienne globalne. Jednak przede wszystkim przegłosowałem, ponieważ nie odpowiedziałeś na pytanie , które dotyczyło użycia lub nie rzutów w stylu C.
DeadMG
2
@DeadMG: Mówiłem o obsadach w stylu C. Cały ostatni akapit uzasadnia rzutowania w stylu C na korzyść static_cast.
Nicol Bolas
„Niestety, moja reguła dotycząca dezaktywacji stałej powodującej, że klawiatura podnosi się i łamie palec programisty, nie została zatwierdzona”. Z technicznego punktu widzenia kompilator może to zrobić. Jak to jest legalne, że kompilator sprawia, że ​​demony wylatują z twojego nosa .
Pharap
3

To zależy od tego, z jakim językiem pracuję, ponieważ wiesz, co mówią: w Rzymie mów po rzymsku. Więc jeśli programuję w C, próbuję maksymalnie wykorzystać funkcje C, ale jeśli programuję w C ++, używam funkcji C ++ do maksimum, nawet jeśli niektórym ludziom się to nie podoba, ponieważ mówią, że czyni to kod „mniej przenośnym”, mówię, że mnie to nie obchodzi, jestem w C ++ i programuję w C ++, a do kompilacji kodu potrzebuję kompilatora w pełni kompatybilnego z C ++, w przeciwnym razie pracowałbym z czymś innym na pierwszym miejscu.

Coyote21
źródło
Naprawdę nie działa, próbując używać rzutów w stylu C ++ w C ;-)
Steve314
3

static_cast itp. zostały wymyślone z powodu problemów z rzutami w stylu C, gdy są używane w szablonach. Jeśli piszesz szablon lub kod może zostać później przekonwertowany na szablon, dobrym pomysłem jest użycie rzutowań w stylu C ++. Powodem jest to, że rzutowania w stylu C ++ lepiej wyrażają zamiary, więc dają oczekiwane wyniki w przypadkach, gdy rzutowania w stylu C zrobią coś złego (biorąc pod uwagę określone typy jako parametry szablonu).

Poza tym mówię, że używaj rzutów w stylu C ++, jeśli masz konkretny problem, który ich potrzebuje - Dynamic_cast jest najczęstszy, ale nawet to prawdopodobnie nie jest codziennością.

Wszystko inne, a obsada w stylu C może być nieco mniej zagracona i poprawiać czytelność, a może nie zależy od tego, jak czytelnik jest zaznajomiony z tym stylem obsady w dzisiejszych czasach. Moim zdaniem nie jest to tak naprawdę ważne, głównie osobiste preferencje, choć nie zdziw się, jeśli niektórzy ludzie nie lubią stylu C.

Ostatnia uwaga - jeśli potrzebujesz tak wielu rzutów, że to wielka sprawa, prawdopodobnie robisz coś innego źle. W niektórych przypadkach są wyjątki, ale większość kodów wysokiego poziomu nie powinna wymagać wielu (jeśli w ogóle) rzutowań.

Steve314
źródło