Există cinci moduri diferite de a face variabile. Există o suprapunere între ele, în special cu distribuția în stil C și toate celelalte distribuții, dar fiecare are utilizarea sa. Este bine să le învățați pe toți, astfel încât să puteți folosi cea mai bună castă pentru nevoia dvs. specială, decât să folosiți orice distribuție care se întâmplă să funcționeze. Dacă aveți nevoie vreodată de o referință rapidă, recomand acest post pe StackOverflow.
Nu discut aici o distribuție implicită pentru simplul motiv că este un concept de bază cu un număr aproape nelimitat de variații. Dacă scriu float f = 10;
Am exprimat implicit un număr întreg la un flotor și i-am păstrat rezultatul în f. De asemenea, puteți arunca implicit un obiect de tip B la un pointer la clasa sa de bază A utilizând adresa operatorului sau la o referință la clasa sa de bază A, efectuând o atribuire obișnuită.
const_cast
Operatorul const_cast poate adăuga și elimina const și volatile. Utilizarea acestuia pentru a adăuga oricare dintre aceste atribute este bine. E rar că ai fi, dar dacă o faci, poți.
Capacitatea lui de a elimina const este ceva ce nu ar trebui să utilizați niciodată într-un program C ++, cu excepția cazului în care trebuie să apelați o funcție de limbaj C care nu respectă const-corectitudinea, dar nu modifică deloc obiectul. Dacă o funcție are un parametru const și aruncă constanța acesteia folosind const_cast, funcția încalcă contractul implicit că nu va modifica parametrul. Așadar, depinde de dvs. ca autor al acestei funcții pentru a vă asigura că nu veți modifica obiectul; în caz contrar, nu ar trebui să utilizați const pentru parametru deoarece veți modifica obiectul.
Dacă vreodată trebuie să folosiți const_cast și un alt operator pentru același obiect, utilizați ultimul const_cast, deoarece eliminarea const-ness de la un obiect ar putea permite schimbări neintenționate să aibă loc dacă ați folosit o distribuție ulterioară.
static_cast
Operatorul static_cast este util pentru turnare:
În general, ori de câte ori se distribuie tipuri fundamentale altor tipuri fundamentale, utilizați static_cast. De obicei, static_cast ar trebui să fie prima dvs. alegere de distribuții, deoarece face tot verificarea pe care o poate face la momentul compilării, astfel încât să nu fi adăugat verificarea run-time pentru a încetini programul.
dynamic_cast
Operatorul dynamic_cast este util pentru turnarea prin moștenire virtuală. static_cast poate arunca de la o clasă derivată la o clasă de bază, indiferent dacă moștenirea este virtuală sau nu. Spuneți însă că vă este dat un obiect de tip A, dar știi că acesta este de fapt un obiect de tip B - și că B moștenește practic de la A. Dacă doriți să aruncați acest obiect înapoi la B pentru a utiliza funcțiile membre care doar B prevede, trebuie să utilizați dynamic_cast.
Câteva lucruri despre dynamic_cast. Mai întâi, acesta funcționează numai pe conversiile pointer-la-pointer sau referință-referință. În al doilea rând, nu poate arunca un obiect de la A la B dacă obiectul nu este, de fapt, un B (sau un tip derivat din B). Un pointer-spre-pointer dinamic_cast care nu reușește întoarce nul. Un eșec referință la referință aruncă o std :: bad_cast
excepție.
reinterpret_cast
Operatorul reinterpret_cast este o conversie directă cu foarte puține utilizări bune. Majoritatea operațiunilor sale dau rezultate nedefinite. Ce înseamnă acest lucru în practică este că trebuie să citiți documentația vânzătorului de compilatoare înainte de ao folosi pentru orice.
O folosesc pentru asta, așa cum am văzut StorageDurationSample
, este de a arunca un pointer la un număr întreg suficient de mare pentru ao ține. Aceasta oferă adresa de memorie a indicatorului, care poate fi utilă pentru depanarea și urmărirea operațiilor în care puteți să aruncați date în fișierele de jurnal și să creați gropi de bază, dar este posibil să nu puteți rula cu ușurință un program de depanare. Veți vedea că este folosit în mod legitim pentru alte scopuri, dar, în general, ar trebui să fie considerat ca o piesă de ultimă instanță (cu excepția unei distribuții în stil C, care vine după reinterpret_cast).
Stilul C, (de ex., auto someData = (SomeType) dataOfSomeOtherType;
) nu este prietenul tău. Sunteți fără îndoială familiarizați cu asta de la C #, unde este foarte util. În C #, dacă încercați să realizați o distribuție folosind acea sintaxă și distribuția este nevalidă, veți produce un InvalidCastException. Acest lucru se întâmplă deoarece CLR ține evidența tipurilor de tot ceea ce ați creat și detectează rezultate rele.
C ++ nu verifică dacă distribuția dvs. în stil C este validă, presupunând că se compilează, bineînțeles. C ++ tocmai presupune că este. Dacă este o distribuție proastă și ai noroc, programul tău se va prăbuși imediat. Dacă nu, veți ajunge cu date într-o stare necunoscută, care va fi cu siguranță coruptă în moduri subtile și insidioase.
În plus, spre deosebire de alte distribuții, pe care le puteți observa cu ușurință prin căutarea _cast<, C-style casts do not stick out. When you're scanning lots of code quickly, parentheses wrapped around text looks as much like a function call as it does a cast operation. You could use a regular expression search for this in Visual Studio 2012: \(.*\)[A-Za-z]. Even so, you are still forgoing all the benefits and protections of the other casts.
Singurul lucru pe care o distribuție în stil C îl poate face nu poate fi alcătuirea unui obiect la una din clasele de bază protejate sau de moștenire privată. Tu chiar nu ar trebui să faci asta deoarece, dacă ai nevoie de moștenire publică, ar trebui să folosești moștenirea publică.
Pe scurt, nu utilizați casturi în stil C.
Există un exemplu, CastingSample, care demonstrează multe tipuri posibile de turnare. Acesta este inclus cu codul sursă pentru această serie. Din motive de scurtătate, îl omitem aici.
În acest articol, am acoperit turnarea în C ++ și sper că este clar că nu ar trebui să folosiți turnuri în stil C. Următorul articol se mări pe șirurile din C++.
Această lecție reprezintă un capitol din C ++ Succinctly, o carte electronică gratuită de la echipa de la Syncfusion.