Kada turėtų būti naudojamas statinis_pasaulis, dinaminis_pasaulis, const_cast ir reinterpret_cast?

Kas yra tinkamas naudojimas:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • C stiliaus (type)value
  • type(value) liejimas

Kaip nuspręsite, kokiais atvejais naudoti?

2153
01 дек. nustatė e.James 01 Dec. 2008-12-01 23:11 '08 at 11:11 pm 2008-12-01 23:11
@ 8 atsakymai

static_cast yra pirmasis, kurį turėtumėte pabandyti naudoti. Tai daro tokius dalykus kaip netiesioginiai konversijos tarp tipų (pvz., Nuo int iki float arba rodyklės į void* ), taip pat ji gali skambinti aiškiomis konversijos funkcijomis (arba netiesioginėmis). Daugeliu atvejų static_cast nėra aiškiai nurodytas, tačiau svarbu pažymėti, kad sintaksė T(something) lygiavertė (T)something ir turėtų būti vengiama (daugiau apie tai vėliau). T(something, something_else) yra saugus ir vis dėlto garantuotas skambinti konstruktoriui.

static_cast taip pat gali būti atliekamas per paveldėjimo hierarchijas. Tai nebūtina, kai mesti (į pagrindinę klasę), bet nuleidžiant jį galima naudoti, kol ji paveldės virtual paveldą. Tačiau patvirtinimas nėra atliekamas, o elgesys, neapibrėžtas naudojant static_cast hierarchijoje, yra tokio tipo, kuris iš tikrųjų nėra objekto tipas.


const_cast gali būti naudojamas, kad pašalintumėte arba pridėtumėte į kintamąjį; nė vienas kitas C ++ metodas negali jį pašalinti (netgi reinterpret_cast ). Svarbu pažymėti, kad ankstesnės const reikšmės pokytis yra neapibrėžtas, jei pradinis kintamasis const ; jei jį naudojate, kad pašalintumėte const nuorodą į kažką, kuris nebuvo deklaruotas naudojant const , jis yra saugus. Tai gali būti naudinga, pavyzdžiui, perkrovus nario funkcijas, pagrįstas const . Jis taip pat gali būti naudojamas const pridėti prie objekto, pavyzdžiui, norint paskambinti nario funkcijos perkrovimui.

const_cast taip pat veikia panašiai kaip volatile , nors tai mažiau paplitusi.


dynamic_cast naudojamas beveik vien tik polimorfizmui apdoroti. Galite perkelti rodyklę arba nuorodą į bet kokį polimorfinį tipą bet kokio kito tipo klasėje (polimorfinis tipas turi bent vieną virtualią funkciją, kuri yra deklaruota arba paveldėta). Jūs galite jį naudoti daugiau nei tik mesti jį žemyn - galite mesti jį į šoną ar net kitą grandinę. dynamic_cast ieškos norimo objekto ir, jei įmanoma, grąžins jį. Jei to nepavyksta, nullptr atveju jis grąžins nullptr arba nuorodos atveju mesti std::bad_cast .

dynamic_cast turi tam tikrų apribojimų. Jis neveikia, jei paveldėjimo hierarchijoje yra keletas to paties tipo objektų (vadinamasis „baisus deimantas“), o jūs nenaudojate virtual paveldėjimo. Ji taip pat gali pereiti tik per viešąjį paveldą - ji visada bus protected arba private per paveldėjimą. Tai retai problema, nes tokios paveldėjimo formos yra retos.


reinterpret_cast yra pavojingiausia mesti ir turėtų būti naudojama labai retai. Vienas tipas tiesiogiai paverčiamas kitu - pavyzdžiui, iš vieno rodyklės į kitą pašalinant vertę arba išsaugant žymeklį į int ir visus kitus nemalonius dalykus. Iš esmės vienintelė garantija, kurią gaunate su reinterpret_cast yra ta, kad, jei grįžtate atgal į pradinį tipą, gausite tą pačią vertę (bet ne, jei tarpinis tipas yra mažesnis už pradinį tipą). Yra daugybė transformacijų, kurių reinterpret_cast negali atlikti. Jis buvo naudojamas pirmiausia ypač keistoms transformacijoms ir manipuliacijoms su bitais, pvz., Neapdorotų duomenų srauto pavertimas faktiniais duomenimis arba duomenų saugojimas žemesnėse lyginamojo žymeklio bituose.


<style>> stiliaus sąrašas yra atitinkamai (type)object arba type(object) . C stiliaus sąrašas apibrėžiamas kaip pirmasis iš šių variantų:

  • const_cast
  • static_cast (nepaisydamas prieigos apribojimų)
  • static_cast (žr. aukščiau), tada const_cast
  • reinterpret_cast
  • reinterpret_cast , tada const_cast

Kai kuriais atvejais jis gali būti naudojamas kaip kitų vaiduoklių pakaitalas, tačiau jis gali būti labai pavojingas, nes gali pereiti prie reinterpret_cast , o pastaroji turėtų būti pageidautina, kai reikalingas aiškus static_cast jei nesate tikri, kad static_cast bus sėkmingas, arba reinterpret_cast baigsis netyčia. Net tada apsvarstykite ilgesnį, aiškesnį variantą.

„C“ stilius taip pat ignoruoja prieigos valdymą atliekant static_cast , o tai reiškia, kad jie turi galimybę atlikti operaciją, kurios negali atlikti jokia kita forma. Tai daugiausia kludas, ir, mano nuomone, tai yra dar viena priežastis, kodėl reikia vengti „C“ stiliaus.

2286
01 дек. atsakymas duodamas 01 d. 2008-12-01 23:26 '08 at 23:26 pm 2008-12-01 23:26

Naudokite dynamic_cast konvertuoti rodykles / nuorodas į paveldėjimo hierarchiją.

Naudokite static_cast norite reguliariai atlikti konversijas.

border=0

Naudokite reinterpret_cast mažo lygio bitų modelių interpretavimui. Naudokite labai atsargiai.

Naudokite const_cast kad sumažintumėte const/volatile . Venkite to, jei nenorite naudoti neteisingo API.

298
01 дек. Fred Larson atsakymas, gruodžio 1 d. 2008-12-01 23:22 '08 at 11:22 2008-12-01 23:22

(Pirmiau pateikti daug teorinių ir konceptualių paaiškinimų)

Toliau pateikiami keli praktiniai pavyzdžiai, kai naudoju statinį_pasaulį , dinaminį_pasaulį , const_cast , reinterpret_cast .

(Taip pat daroma nuoroda į šį paaiškinimą: 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 янв. atsakymą pateikė Sumit Arora, sausio 21 d 2014-01-21 07:53 '14, 7:53, 2014-01-21 07:53

Tai gali padėti, jei žinote šiek tiek vidaus ...

statinis_pasaulis

  • C ++ kompiliatorius jau žino, kaip keisti mastelio tipus, tokius kaip plūdės, į int. Naudokite static_cast jiems.
  • Kai paprašote kompiliatoriaus konvertuoti tipą A į B , static_cast skambučio konstruktorių B perduoda A kaip parametrą. Alternatyviai, A gali turėti transformavimo operatorių (t.y., A::operator B() ). Jei B neturi tokio konstruktoriaus arba A neturi transformatoriaus operatoriaus, gausite kompiliavimo laiko klaidą.
  • Konvertavimas iš A* į B* visada sėkmingas, jei A ir B yra paveldėjimo (arba negaliojančio) hierarchijoje, kitaip gausite kompiliavimo klaidą.
  • Korekcija : jei pamatinį žymeklį nukreipiate į gautą rodyklę, bet jei faktinis objektas nėra išvestinis tipas, klaidos nebus. Gausite blogą rodiklį ir greičiausiai - pertraukos metu. Tas pats pasakytina apie A> B> .
  • Turite : dauguma išvestų į bazę arba atvirkščiai sukurs naują kopiją! Žmonėms, atvykusiems iš „C # / Java“, tai gali būti didžiulis siurprizas, nes rezultatas iš esmės yra atskirtas objektas, sukurtas iš „Derived“.

dynamic_cast

  • dynamic_cast naudoja runtime tipo informaciją, kad nustatytų, ar rinkinys yra tinkamas. Pavyzdžiui, nuo (Base*) iki (Derived*) gali nepavykti, jei žymeklis iš tikrųjų nėra išvestas tipas.
  • Tai reiškia, kad dinaminis_pasaulis yra labai brangus, palyginti su statiniu_pasauliu!
  • Jei A* yra B* , jei perteikimas yra neteisingas, tada „dinaminis“ bus grąžintas nullptr.
  • Jei „ A> B> jei perteikimas yra neteisingas, dinaminis „cast_cast “išmeta išimtį„ blogas “.
  • Skirtingai nuo kitų vaiduoklių, yra runtime overhead.

const_cast

  • Nors statinis rodymas gali atlikti pastovias konstantas, jis negali sekti kito kelio. „Const_cast“ gali dirbti abiem kryptimis.
  • Vienas iš pavyzdžių, kai tai patogu, yra kartoti per konteinerį, pavyzdžiui, set<T> kuris grąžina tik jo elementus kaip const, kad įsitikintumėte, jog nepakeitėte jo rakto. Tačiau, jei ketinate keisti nepagrindinius objekto narius, tada viskas turėtų būti gerai. Galite naudoti const_cast pašalinti konstantumą.
  • Kitas pavyzdys yra, kai norite įgyvendinti T foo() ir const T foo() . Norėdami išvengti kodų dubliavimo, galite naudoti const_cast, kad grąžintumėte vienos funkcijos vertę iš kito.

reinterpret_cast

  • Iš esmės jis sako, kad šie baitai yra šioje atminties vietoje ir laikomi tam tikru objektu.
  • Pvz., Galite įkelti 4 baitus su kintamu tašku iki 4 baitų, kad matytumėte, kokie bitai atrodo kaip plūduriuojantis taškas.
  • Akivaizdu, kad jei duomenys neatitinka tipo, galite gauti segfault.
  • Šiam traukiniui nėra prijungimo laiko.
65
11 дек. atsakymą pateikė ShitalShah 11 d. 2016-12-11 05:05 '16 at 5:05 am 2016-12-11 05:05

Ar tai padeda atsakyti į jūsų klausimą?

Aš niekada nenaudojau reinterpret_cast , ir man įdomu, ar jis veikia tuo atveju, kai jam reikia, jis nėra kvapo dizaino kvapas. Kodo bazėje dirbau dynamic_cast . Skirtumas nuo static_cast yra tas, kad dinaminis_paslapis atlieka vykdymo patikrinimą, kuris gali būti (saugesnis) arba gali būti ne didesnis (viršutinis), ką norite (žr. Msdn ).

12
01 дек. atsakymas duotas andreas buykx 01 dec. 2008-12-01 23:20 '08 at 11:20 2008-12-01 23:20

Be likusių atsakymų, vis dar yra static_cast pavyzdys, kai static_cast , todėl reikalingas reinterpret_cast . Tarkime, yra funkcija, kuri išėjimo parametre grąžina rodykles į skirtingų klasių objektus (kurie neturi bendros bazinės klasės). Tikras tokios funkcijos pavyzdys yra „ CoCreateInstance() (žr. Paskutinis parametras, kuris iš tikrųjų yra void** ). Tarkime, kad iš šios funkcijos prašote tam tikros objektų klasės, todėl iš anksto žinote žymeklio tipą (kurį dažnai darote COM objektams). Tokiu atveju rodyklę negalite priskirti žymeklį į void** naudodami static_cast : reikia iš reinterpret_cast<void**>(> .

Kode:

 #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**>( ); 

Tačiau static_cast veikia paprastiems rodikliams (ne rodyklėms), todėl aukščiau nurodytas kodas gali būti perrašytas, kad būtų išvengta reinterpret_cast (papildomo kintamojo kaina):

 #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 atsakymą pateikė Serge Rogatch gegužės 15 d. 17:16 2015-05-31 17:16

Nors kiti atsakymai gerai apibūdino visus skirtumus tarp „C ++“ kastų, norėčiau pridėti trumpą pastabą, kodėl neturėtumėte naudoti „C“ stiliaus (Type) var ir Type(var) .

„C + +“ pradedantiesiems C stilius atrodo kaip „C ++“ („Static_cast“ <> (), dynamic_cast <> (), const_cast <> (), reinterpret_cast <> () ir „C + +“. Tiesą sakant, C stilius yra superset ir trumpesnis rašyti.

Pagrindinė C stiliaus įvedimo problema yra tai, kad jie slėpia tikrąjį kūrėjo ketinimą kūrimo metu. C stiliaus stiliai gali atlikti beveik visų tipų liejimą iš įprastų saugių šiukšlių, kuriuos static_cast <> () ir dynamic_cast <> () į potencialiai pavojingus vaidmenis, tokius kaip const_cast <> (), kur const modifikatorius gali būti pašalintas, todėl pastovus kintamieji gali būti keisti ir reinterpret__cast <> (), kurie netgi gali iš naujo interpretuoti sveikojo skaičiaus reikšmes į rodykles.

Čia yra pavyzdys.

 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. 

Pagrindinė priežastis, kodėl C ++ buvo pridėta prie kalbos, buvo leisti kūrėjui paaiškinti savo ketinimus - kodėl jis ketina tai padaryti. Naudodami „C“ stilių, kurie puikiai tinka „C ++“, jūs padarote savo kodą mažiau skaitomą ir labiau linkę į klaidas, ypač kitiems kūrėjams, kurie nesukūrė kodo. Todėl, norėdami padaryti kodą aiškesnį ir aiškesnį, visada turėtumėte pirmenybę C + + per daugiau nei C stiliaus stilių.

Čia pateikiamas trumpas Bjarne Stroustrup (C ++ autorius) 4-ojo leidinio C ++ programavimo kalbos citata, p.

Šis „C“ stiliaus pasirinkimas yra daug pavojingesnis už pavadintą transformatorių operatorių, nes rašymas į sudėtingą programą yra sudėtingesnis, o programuotojui skirtas konversijos tipas nėra aiškus.

6
22 авг. Atsakymą pateikė Timmy_A 22 rug . 2018-08-22 14:18 '18, 14:18 pm 2018-08-22 14:18

Norėdami suprasti, žiūrėkime toliau pateiktą kodo fragmentą:

 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; } 

Tik klaidos eilutėje yra tik eilutė (4). Naudojant tik reinterpret_cast galima konvertuoti rodyklę į objektą į rodiklį į bet kokį nesusijusį objekto tipą.

Reikėtų atkreipti dėmesį į tai, kad dinaminis transliavimas neveiks vykdymo metu, tačiau daugumoje kompiliatorių jis nebus sukompiliuotas, nes konvertuojamo rodyklės struktūra neturi virtualių funkcijų, ty, dinaminis_cast veiks tik su polimorfiniais klasės rodikliais.

Kada naudoti C ++ :

  • Naudokite „ static_cast“ kaip C tipo konversijos ekvivalentą, kuris konvertuoja reikšmes, arba kai mes turime aiškiai konvertuoti rodyklę iš klasės į savo klasę.
  • Naudokite const_cast pašalinti const kvalifikaciją.
  • Naudokite „ reinterpret_cast “ nesaugaus žymeklio tipo konvertavimui į sveikąjį skaičių ir iš kitų rodyklų tipų ir atvirkščiai. Naudokite tai tik tada, jei žinome, ką darome, ir suprantame slapyvardžių problemas.
0
21 дек. Atsakymą pateikė Pankaj Kumar Thapa . 2018-12-21 05:53 '18, 5:53 2018-12-21 05:53

Kiti klausimai apie „ etiketes, „ arba „ Klauskite“