Hva er riktig bruk av:
static_cast
dynamic_cast
const_cast
(type)value
(verdi)type(value)
(funksjonstype)Hvordan bestemmer man hvilken som skal brukes i hvilke spesifikke tilfeller?
static_cast
er den første casten du bør forsøke å bruke. Den gjør ting som implisitte konverteringer mellom typer (som int
til float
, eller peker til void*
), og den kan også kalle eksplisitte konverteringsfunksjoner (eller implisitte). I mange tilfeller er det ikke nødvendig å eksplisitt angi static_cast
, men det er viktig å merke seg at syntaksen T(something
er ekvivalent med (T)something
og bør unngås (mer om det senere). En T(noe, noe_annet)
er imidlertid sikker, og vil garantert kalle konstruktøren.
static_cast
kan også kaste gjennom arvehierarkier. Det er unødvendig når det castes oppover (mot en basisklasse), men når det castes nedover kan det brukes så lenge det ikke castes gjennom virtuell
arv. Det sjekker imidlertid ikke, og det er udefinert oppførsel å static_cast
nedover i et hierarki til en type som faktisk ikke er typen til objektet.
const_cast
kan brukes til å fjerne eller legge til const
til en variabel; ingen andre C++ cast er i stand til å fjerne den (ikke engang reinterpret_cast
). Det er viktig å merke seg at endring av en tidligere const
-verdi bare er udefinert hvis den opprinnelige variabelen er const
; hvis du bruker den til å ta const
av en referanse til noe som ikke ble deklarert med const
, er det trygt. Dette kan være nyttig når du overbelaster medlemsfunksjoner basert på const
, for eksempel. Det kan også brukes til å legge const
til et objekt, for eksempel for å kalle en medlemsfunksjon overload.
const_cast
fungerer også på samme måte på volatile
, selv om det er mindre vanlig.
dynamic_cast
brukes utelukkende for å håndtere polymorfisme. Du kan caste en peker eller referanse til en hvilken som helst polymorf type til en hvilken som helst annen klassetype (en polymorf type har minst én virtuell funksjon, deklarert eller nedarvet). Du kan bruke den til mer enn bare å kaste nedover - du kan kaste sidelengs eller til og med opp en annen kjede. Den dynamiske_kast
vil søke opp det ønskede objektet og returnere det hvis mulig. Hvis den ikke kan, vil den returnere nullptr
i tilfelle av en peker, eller kaste std::bad_cast
i tilfelle av en referanse.
dynamic_cast
har imidlertid noen begrensninger. Det fungerer ikke hvis det er flere objekter av samme type i arvehierarkiet (den såkalte 'fryktede diamanten') og du ikke bruker virtuell
arv. Det kan også bare gå gjennom offentlig arv - det vil alltid mislykkes i å reise gjennom beskyttet
eller privat
arv. Dette er imidlertid sjelden et problem, ettersom slike former for arv er sjeldne.
reinterpret_cast
er den farligste kastet, og bør brukes svært sparsomt. Det gjør en type direkte til en annen - for eksempel å kaste verdien fra en peker til en annen, eller lagre en peker i en int
, eller alle slags andre stygge ting. Stort sett er den eneste garantien du får med reinterpret_cast
at normalt hvis du kaster resultatet tilbake til den opprinnelige typen, vil du få nøyaktig samme verdi (men ikke hvis den mellomliggende typen er mindre enn den opprinnelige typen). Det er også en rekke konverteringer som reinterpret_cast
ikke kan gjøre. Den brukes først og fremst til spesielt rare konverteringer og bitmanipulasjoner, som å gjøre en rådatastrøm om til faktiske data, eller lagre data i de lave bitene i en peker til justerte data.
C-style cast og function-style cast er cast som bruker henholdsvis (type)object
eller type(object)
, og er funksjonelt ekvivalente. De er definert som den første av de følgende som lykkes:
const_cast
static_cast
(men ignorerer tilgangsbegrensninger)static_cast
(se ovenfor), deretter const_cast
.reinterpret_cast
, deretter const_cast
.Det kan derfor brukes som en erstatning for andre cast i noen tilfeller, men kan være ekstremt farlig på grunn av evnen til å utvikle seg til en reinterpret_cast
, og sistnevnte bør foretrekkes når eksplisitt casting er nødvendig, med mindre du er sikker på at static_cast
vil lykkes eller reinterpret_cast
vil mislykkes. Selv da bør du vurdere det lengre, mer eksplisitte alternativet.
C-style casts ignorerer også tilgangskontroll når de utfører en static_cast
, noe som betyr at de har muligheten til å utføre en operasjon som ingen andre cast kan. Dette er for det meste en kludge, skjønt, og i mitt sinn er bare en annen grunn til å unngå C-stil kaster.
Bruk dynamic_cast
for å konvertere pekere/referanser innenfor et nedarvingshierarki.
Bruk static_cast
for vanlige typekonverteringer.
Bruk reinterpret_cast
for refortolkning av bitmønstre på lavt nivå. Brukes med ekstrem forsiktighet.
Bruk const_cast
for å kaste bort const/volatile
. Unngå dette med mindre du sitter fast med et const-incorrect API.
Besvarer dette spørsmålet ditt?
Jeg har aldri brukt reinterpret_cast
, og lurer på om det å kjøre inn i et tilfelle som trenger det ikke er en lukt av dårlig design. I kodebasen jeg jobber med brukes dynamic_cast
mye. Forskjellen med static_cast
er at en dynamic_cast
gjør kjøretidskontroll som kanskje (sikrere) eller kanskje ikke (mer overhead) er det du ønsker (se msdn).