Kada treba koristiti static_cast, dynamic_cast, const_cast i reinterpret_cast?

Koja je ispravna upotreba:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • C- (type)value
  • type(value) lijevanje stila

Kako odlučujete što ćete koristiti u kojim slučajevima?

2153
01 дек. postavila e.James 01. prosinca 2008-12-01 23:11 '08 u 23:11 2008-12-01 23:11
@ 8 odgovora

static_cast je prvi odljev koji trebate upotrijebiti. Radi stvari poput implicitnih konverzija između tipova (na primjer, od int do float ili pokazivača na void* ), a može također pozvati eksplicitne funkcije konverzije (ili implicitne). U mnogim slučajevima, static_cast nije izričito naveden, ali je važno napomenuti da je sintaksa T(something) ekvivalentna (T)something i treba je izbjegavati (više o tome kasnije). T(something, something_else) je sigurno i, ipak, zajamčeno naziva konstruktora.

static_cast se također može izvršiti putem hijerarhija nasljeđivanja. To nije potrebno prilikom podizanja (prema osnovnoj klasi), ali se prilikom pada može koristiti dok ne naslijedi virtual nasljeđivanje. Međutim, provjera valjanosti se ne provodi, a ponašanje koje nije definirano static_cast prema hijerarhiji je tipa koji zapravo nije tip objekta.


const_cast se može koristiti za uklanjanje ili dodavanje const u varijablu; nijedan drugi C ++ metod nije u mogućnosti da ga ukloni (čak ni reinterpret_cast ). Važno je napomenuti da je promjena prethodne vrijednosti const samo nedefinirana ako je inicijalna varijabla const ; ako ga koristite za uklanjanje const veze na nešto što nije deklarirano pomoću const , sigurno je. To može biti korisno, na primjer, kada se preopterećuju funkcije člana utemeljene na const . Također se može koristiti za dodavanje const u objekt, na primjer, za pozivanje preopterećenja funkcije člana.

const_cast također radi slično volatile , iako je to manje uobičajeno.


dynamic_cast koristi gotovo isključivo za obradu polimorfizma. Možete preklopiti pokazivač ili vezu na bilo koji polimorfni tip na bilo kojoj drugoj vrsti klase (polimorfni tip ima najmanje jednu virtualnu funkciju koja je deklarirana ili naslijeđena). Možete ga upotrijebiti više nego samo baciti - možete ga baciti u stranu ili čak u drugi lanac. dynamic_cast će tražiti željeni objekt i, ako je moguće, vratiti ga. Ako ne može, vratit će nullptr u slučaju pokazivača ili baciti std::bad_cast u slučaju veze.

dynamic_cast ima neka ograničenja. Ne radi ako postoji nekoliko objekata istog tipa u hijerarhiji nasljeđivanja (takozvani "zastrašujući dijamant"), a vi ne koristite virtual nasljeđivanje. Također može proći samo kroz javno nasljeđe - ono će uvijek nositi protected ili private nasljedstvo. To je rijetko problem, jer su takvi oblici nasljeđivanja rijetki.


reinterpret_cast je najopasnije bacanje i treba ga koristiti vrlo štedljivo. Ona pretvara jedan tip izravno u drugi - na primjer, odbacivanjem vrijednosti s jednog pokazivača na drugi ili spremanjem pokazivača na int ili sve druge neugodne stvari. U osnovi, jedino jamstvo koje dobijete s reinterpret_cast je da obično, ako vratite rezultat natrag na izvorni tip, dobit ćete istu vrijednost (ali ne ako je srednji tip manji od izvornog tipa). Postoje brojne transformacije koje reinterpret_cast ne može izvesti. On se primarno koristio za osobito čudne transformacije i manipulacije bitovima, kao što je pretvaranje sirovog podatkovnog toka u stvarne podatke ili pohranjivanje podataka u niže bitove poravnanog pokazivača.


<style>> popis stilova je (type)object ili type(object) . Popis C-stila definiran je kao prvi od sljedećih, koji uspijeva:

  • const_cast
  • static_cast (iako zanemarivanje ograničenja pristupa)
  • static_cast (vidi gore), zatim const_cast
  • reinterpret_cast
  • reinterpret_cast , zatim const_cast

U nekim slučajevima, može se koristiti kao zamjena za druge duhove, ali može biti vrlo opasno zbog mogućnosti da se uđe u reinterpret_cast , a drugo treba dati prednost kada je eksplicitno lijevanje potrebno ako niste sigurni da će static_cast uspjeti, ili će se reinterpret_cast završiti s greškom. Čak i tada razmotrite dulju, eksplicitniju opciju.

C-stil static_cast također zanemaruje kontrolu pristupa pri izvođenju static_cast , što znači da imaju mogućnost izvođenja operacije koju ne može izvesti nijedan drugi cast. To je uglavnom kludge, i po mom mišljenju, to je još jedan razlog da se izbjegne C-style cast.

2286
01 дек. odgovor je dan coppro 01 dec. 2008-12-01 23:26 '08 u 23:26 2008-12-01 23:26

Koristite dynamic_cast za pretvaranje pokazivača / veza u hijerarhiju nasljeđivanja.

Koristite static_cast za uobičajene pretvorbe vrsta.

border=0

Koristite reinterpret_cast za reinterpret_cast niske razine uzoraka bitova. Koristite s velikim oprezom.

Koristite const_cast da ispustite const/volatile . Izbjegavajte ovo ako niste zaglavili pomoću netočnog API-ja.

298
01 дек. Odgovor koji je dao Fred Larson 01. prosinca 2008-12-01 23:22 '08 u 11:22 2008-12-01 23:22

(Mnoga su teorijska i konceptualna objašnjenja dana gore)

U nastavku su navedeni neki od praktičnih primjera kada sam koristio static_cast , dynamic_cast , const_cast , reinterpret_cast .

(Također upućuje na to kako bi razumio objašnjenje: http://www.cplusplus.com/doc/tutorial/typecasting/ )

static_cast:

 OnEventData(void* pData) { ...... // pData is a void* pData, // EventData is a structure eg // typedef struct _EventData { // std::string id; // std:: string remote_id; // } EventData; // On Some Situation a void pointer *pData // has been static_casted as // EventData* pointer EventData *evtdata = static_cast<EventData*>(pData); ..... } 

dynamic_cast:

 void DebugLog::OnMessage(Message *msg) { static DebugMsgData *debug; static XYZMsgData *xyz; if(debug = dynamic_cast<DebugMsgData*>(msg->pdata)){ // debug message } else if(xyz = dynamic_cast<XYZMsgData*>(msg->pdata)){ // xyz message } else{ // ... } } 

const_cast:

 // *Passwd declared as a const const unsigned char *Passwd // on some situation it require to remove its constness const_cast<unsigned char*>(Passwd) 

reinterpret_cast:

 typedef unsigned short uint16; // Read Bytes returns that 2 bytes got read. bool ByteBuffer::ReadUInt16(uint16 val) { return ReadBytes(reinterpret_cast<char*>( 2); } 
165
21 янв. odgovor je dao Sumit Arora 21. siječnja 2014-01-21 07:53 '14 u 7:53 2014-01-21 07:53

To može pomoći ako znate malo interne ...

static_cast

  • C ++ prevodilac već zna kako pretvoriti tipove skaliranja, kao što je float, u int. Za njih koristite static_cast .
  • Kada od prevoditelja zatražite da pretvori tip A u B , static_cast poziva konstruktora B prosljeđujući A kao parametar. Alternativno, A može imati operatora transformacije (tj. A::operator B() ). Ako B nema takav konstruktor ili A nema operatora transformacije, dobit ćete grešku vremena prevođenja.
  • Konverzija iz A* u B* uvijek je uspješna ako su A i B u hijerarhiji nasljeđivanja (ili void), inače ćete dobiti pogrešku kompilacije.
  • Ispravak : ako bacite pokazivač baze na izvedeni pokazivač, ali ako stvarni objekt zapravo nije izvedeni tip, nećete dobiti pogrešku. Dobivate loš pokazivač i najvjerojatnije segfault prilikom izvođenja. Isto vrijedi i za A> B> .
  • Dobio : cast iz Derived to Base ili obratno će stvoriti novu kopiju! Za ljude koji dolaze s C # / Jave, to može biti veliko iznenađenje, jer je rezultat u osnovi odsječeni objekt stvoren iz Derived-a.

dynamic_cast

  • dynamic_cast koristi informacije o vrsti izvođenja kako bi odredio je li cast valjan. Na primjer, od (Base*) do (Derived*) možda neće uspjeti ako pokazivač zapravo nije izvedeni tip.
  • To znači da je dynamic_cast vrlo skup u odnosu na static_cast!
  • Za A* do B* , ako je cast pogrešan, tada će dynamic_cast vratiti nullptr.
  • Za A> do B> ako je cast neispravan, onda će dynamic_cast baciti iznimku bad_cast.
  • Za razliku od ostalih duhova, postoji opterećenje za vrijeme izvođenja.

const_cast

  • Dok static_cast može raditi ne-konstantne konstante, ne može slijediti drugi put. Const_cast može raditi u oba smjera.
  • Jedan od primjera gdje je to prikladno je ponavljati kroz spremnik, na primjer, set<T> koji vraća samo svoje elemente kao const, kako bi bili sigurni da niste promijenili njegov ključ. Međutim, ako je vaša namjera da promijenite ne-ključne članove objekta, onda bi sve trebalo biti u redu. Možete koristiti const_cast za uklanjanje constness.
  • Drugi primjer je kada želite implementirati T foo() kao i const T foo() . Da biste izbjegli dupliciranje koda, možete koristiti const_cast za vraćanje vrijednosti jedne funkcije iz druge.

reinterpret_cast

  • To u osnovi kaže da uzeti ove bajtove u ovo memorijsko mjesto i uzeti ga kao zadani objekt.
  • Na primjer, možete učitati 4 bajta s pomičnim zarezom u 4 bajta s cijelim brojem da biste vidjeli kako izgledaju bitovi u pomičnim zarezima.
  • Očito, ako se podaci ne podudaraju s tipom, možete dobiti segfault.
  • Za ovaj vlak nema vremena.
65
11 дек. odgovor daje ShitalShah na 11. prosinca. 2016-12-11 05:05 '16 u 5:05 am 2016-12-11 05:05

Je li to odgovor na vaše pitanje?

Nikada nisam koristio reinterpret_cast , i pitam se radi li u slučaju da mu je potreban, ne miriše na loš dizajn. U bazi koda radim na dynamic_cast . Razlika je u static_cast što dynamic_cast izvodi runtime check, koji može (sigurnije) ili možda ne (više opterećenja) biti ono što želite (vidi msdn ).

12
01 дек. odgovor je dan andreas buykx 01 dec. 2008-12-01 23:20 '08 u 11:20 2008-12-01 23:20

Osim ostalih odgovora, još uvijek postoji static_cast primjer gdje static_cast nije dovoljan, pa je potrebno reinterpret_cast . Pretpostavimo da postoji funkcija koja u izlaznom parametru vraća pokazivače na objekte različitih klasa (koje nemaju zajedničku baznu klasu). Pravi primjer takve funkcije je CoCreateInstance() (vidi Last Parameter, koji je zapravo void** ). Pretpostavimo da od ove funkcije tražite određenu klasu objekata, tako da unaprijed znate vrstu pokazivača (što često radite za COM objekte). U ovom slučaju, ne možete nametnuti pokazivač na pokazivač na void** koristeći static_cast : morate reinterpret_cast<void**>(> .

U kôdu:

 #include <windows.h> #include <netfw.h> ..... INetFwPolicy2* pNetFwPolicy2 = nullptr; HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr, CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2), //static_cast<void**>( would give a compile error reinterpret_cast<void**>( ); 

Međutim, static_cast radi za jednostavne pokazivače (ne pokazivače na pokazivače), tako da se gornji kod može prepisati kako bi se izbjeglo reinterpret_cast (po cijeni dodatne varijable) kako slijedi:

 #include <windows.h> #include <netfw.h> ..... INetFwPolicy2* pNetFwPolicy2 = nullptr; void* tmp = nullptr; HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr, CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),  ); pNetFwPolicy2 = static_cast<INetFwPolicy2*>(tmp); 
12
31 мая '15 в 17:16 2015-05-31 17:16 odgovor je dao Serge Rogatch 31. svibnja 2009. u 17:16 2015-05-31 17:16

Dok su drugi odgovori dobro opisali sve razlike između C ++ kasti, htio bih dodati kratku napomenu zašto ne biste trebali koristiti C-style cast (Type) var i Type(var) .

Za početnike u C ++, C-stil izgleda kao superset operacija na C ++ casts (static_cast <> (), dynamic_cast <> (), const_cast <> (), reinterpret_cast <> ()), a netko ih može preferirati preko C ++. Zapravo, C-stil je nadskup i kraći za pisanje.

Glavni problem unošenja C stila je taj što skrivaju pravu namjeru developera tijekom stvaranja. Stilovi stila C mogu izvoditi gotovo sve vrste odljeva iz normalno sigurnog smeća koje obavljaju static_cast <> () i dynamic_cast <> () u potencijalno opasne uloge, kao što je const_cast <> (), gdje se modifikator const može ukloniti, dakle konstantno varijable se mogu modificirati i reinterpret_cast <> (), koje mogu čak i reinterpretirati vrijednosti cijelog do pokazivača.

Ovdje je uzorak.

 int a=rand(); // Random number. int* pa1=reinterpret_cast<int*>(a); // OK. Here developer clearly expressed he wanted to do this potentially dangerous operation. int* pa2=static_cast<int*>(a); // Compiler error. int* pa3=dynamic_cast<int*>(a); // Compiler error. int* pa4=(int*) a; // OK. C-style cast can do such cast. The question is if it was intentional or developer just did some typo. *pa4=5; // Program crashes. 

Glavni razlog zašto je C ++ dodan jeziku bio je omogućiti developeru da razjasni svoje namjere - zašto će to učiniti. Koristeći C-stilove koji su izvrsni u C + +, kôd postaje manje čitljiv i skloniji pogreškama, posebno za druge programere koji nisu stvorili svoj kod. Stoga, da bi vaš kod bio čitljiviji i eksplicitniji, uvijek biste trebali preferirati C ++ nad lijevanjem nad C stilovima.

Evo kratkog citata Bjarne Stroustrup (autor C ++-a) knjige C ++ Programski jezik 4. izdanja - str.

Ovaj C-stil je mnogo opasniji od operatora imenovanog transformiranja, jer je pisanje složenijeg programa složenije, a tip pretvorbe namijenjen programeru nije eksplicitan.

6
22 авг. Odgovor daje Timmy_A 22 aug. 2018-08-22 14:18 '18 u 14:18 sati 2018-08-22 14:18

Da bismo to razumjeli, pogledajte donji kôd koda:

 struct Foo{}; struct Bar{}; int main(int argc, char** argv) { Foo* f = new Foo; Bar* b1 = f; // (1) Bar* b2 = static_cast<Bar*>(f); // (2) Bar* b3 = dynamic_cast<Bar*>(f); // (3) Bar* b4 = reinterpret_cast<Bar*>(f); // (4) Bar* b5 = const_cast<Bar*>(f); // (5) return 0; } 

Samo se redak (4) kompilira bez grešaka. Samo se reinterpret_cast može koristiti za pretvaranje pokazivača na objekt u pokazivač na bilo koji nepovezani tip objekta.

Treba napomenuti sljedeće: dynamic_cast neće raditi za vrijeme izvođenja, međutim na većini kompajlera neće ni kompajlirati, budući da struktura pretvorenog pokazivača nema virtualne funkcije, to jest, dynamic_cast će raditi samo s polimorfnim pokazivačima klase.,

Kada koristiti C ++ cast :

  • Koristite static_cast kao ekvivalent konverzije tipa C koja pretvara vrijednosti ili kada trebamo izričito pretvoriti pokazivač iz klase u njegovu superklasu.
  • Koristite const_cast za uklanjanje const kvalifikatora.
  • Koristite reinterpret_cast za nesigurno pretvaranje tipa pokazivača u cijeli broj i iz drugih vrsta pokazivača i obrnuto. Koristite to samo ako znamo što radimo i razumijemo probleme pseudonima.
0
21 дек. Odgovor daje Pankaj Kumar Thapa 21. prosinca. 2018-12-21 05:53 '18 u 5:53 2018-12-21 05:53

Ostala pitanja o naljepnicama, ili Ask a Question