Hvad er den korrekte anvendelse af:
static_cast
dynamic_cast
const_cast
.reinterpret_cast
.(type)værdi
type(value)
Hvordan beslutter man, hvilken type der skal bruges i hvilke specifikke tilfælde?
static_cast
er den første cast, du skal forsøge at bruge. Den gør ting som implicitte konverteringer mellem typer (såsom int
til float
, eller pointer til void*
), og den kan også kalde eksplicitte konverteringsfunktioner (eller implicitte). I mange tilfælde er det ikke nødvendigt at angive static_cast
eksplicit, men det er vigtigt at bemærke, at syntaksen T(something)
svarer til (T)something
og bør undgås (mere om det senere). En T(something, something_else)
er dog sikker og garanterer, at den kalder konstruktøren.
static_cast
kan også kaste gennem arvehierarkier. Det er unødvendigt når der castes opad (mod en basisklasse), men når der castes nedad kan det bruges, så længe det ikke castes gennem virtuel
arv. Den foretager dog ikke kontrol, og det er udefineret adfærd at static_cast
nedad i et hierarki til en type, som ikke er objektets type.
const_cast
kan bruges til at fjerne eller tilføje const
til en variabel; ingen anden C++-cast er i stand til at fjerne den (ikke engang reinterpret_cast
). Det er vigtigt at bemærke, at ændring af en tidligere const
-værdi kun er udefineret, hvis den oprindelige variabel er const
; hvis du bruger den til at fjerne const
fra en reference til noget, der ikke var deklareret med const
, er det sikkert. Dette kan f.eks. være nyttigt når man overloader medlemsfunktioner baseret på const
. Det kan også bruges til at tilføje const
til et objekt, f.eks. for at kalde en overbelastning af en medlemsfunktion.
const_cast
fungerer også på samme måde på volatile
, selvom det er mindre almindeligt.
dynamic_cast
bruges udelukkende til håndtering af polymorphisme. Du kan caster en pointer eller reference til en polymorf type til en hvilken som helst anden klassetype (en polymorf type har mindst én virtuel funktion, deklareret eller nedarvet). Du kan bruge den til mere end blot at kaste nedad - du kan kaste sidelæns eller endda opad i en anden kæde. dynamic_cast
vil søge efter det ønskede objekt og returnere det, hvis det er muligt. Hvis den ikke kan, vil den returnere nullptr
i tilfælde af en pointer, eller kaste std::bad_cast
i tilfælde af en reference.
dynamic_cast
har dog nogle begrænsninger. Den virker ikke, hvis der er flere objekter af samme type i arvehierarkiet (den såkaldte 'frygtede diamant') og du ikke bruger virtual
-arvning. Det kan også kun gå gennem offentlig arv - det vil altid mislykkes at rejse gennem protected
eller private
arv. Dette er dog sjældent et problem, da sådanne former for arv er sjældne.
reinterpret_cast
er den farligste cast, og bør bruges meget sparsomt. Den forvandler en type direkte til en anden - f.eks. ved at caster værdien fra en pointer til en anden, eller ved at gemme en pointer i en int
, eller alle mulige andre ubehagelige ting. I det store og hele er den eneste garanti du får med reinterpret_cast
, at hvis du normalt caster resultatet tilbage til den oprindelige type, vil du få nøjagtig den samme værdi (men ikke hvis den mellemliggende type er mindre end den oprindelige type). Der er også en række konverteringer, som reinterpret_cast
ikke kan udføre. Den bruges primært til særligt mærkelige konverteringer og bitmanipulationer, som f.eks. at omdanne en rå datastrøm til faktiske data eller gemme data i de lave bits af en pointer til justerede data.
C-style cast og function-style cast er casts ved hjælp af henholdsvis (type)object
eller type(object)
og er funktionelt ækvivalente. De er defineret som den første af følgende, der lykkes:
const_cast
static_cast
(dog uden at tage hensyn til adgangsbegrænsninger)static_cast
(se ovenfor), derefter const_cast
.reinterpret_cast
.reinterpret_cast
, derefter const_cast
.Det kan derfor bruges som en erstatning for andre casts i nogle tilfælde, men kan være ekstremt farligt på grund af muligheden for at udvikle sig til en reinterpret_cast
, og sidstnævnte bør foretrækkes når eksplicit casting er nødvendig, medmindre du er sikker på at static_cast
vil lykkes eller reinterpret_cast
vil mislykkes. Selv da bør du overveje den længere, mere eksplicitte mulighed.
C-style casts ignorerer også adgangskontrol, når de udfører en static_cast
, hvilket betyder at de har mulighed for at udføre en operation, som ingen anden cast kan udføre. Dette er dog mest en kludge, og efter min mening er det blot endnu en grund til at undgå C-style casts.
Brug dynamic_cast
til at konvertere pointere/referencer inden for et arvehierarki.
Brug static_cast
til almindelige type-konverteringer.
Brug reinterpret_cast
til omfortolkning af bitmønstre på lavt niveau. Brug med ekstrem forsigtighed.
Brug const_cast
til at kaste const/volatile
væk. Undgå dette, medmindre du er fanget i at bruge en const-inkorrekt API.
Svarer dette på dit spørgsmål?
Jeg har aldrig brugt reinterpret_cast
, og jeg spekulerer på, om det ikke lugter af dårligt design, hvis jeg støder på et tilfælde, hvor det er nødvendigt. I den kodebase jeg arbejder på bruges dynamic_cast
meget. Forskellen på static_cast
er at en dynamic_cast
laver runtime checking, hvilket måske (mere sikkert) eller måske ikke (mere overhead) er det man ønsker (se msdn).