Ce face static_cast, dynamic_cast, const_cast, reinterpret_cast
static_cast este conversia de zi cu zi: double în int, int în enum, pointer la clasa de bază în pointer la clasa derivată (fără verificare). Se verifică la compilare.
dynamic_cast transformă un pointer sau o referință la o clasă de bază polimorfică (cu funcții virtuale) într-un pointer la o clasă derivată și verifică la rulare dacă obiectul chiar este de acel tip. Pentru pointeri returnează nullptr dacă nu este; pentru referințe aruncă std::bad_cast.
const_cast adaugă sau scoate const, de obicei ca să apelezi o funcție veche care nu a fost scrisă cu const. reinterpret_cast privește aceiași biți ca alt tip (pointer ca număr, obiect ca octeți); este periculos și rar necesar. Vechea conversie în stil C, (int)x, încearcă pe rând toate acestea, deci ascunde ce se întâmplă de fapt.
Exemple
Exemplul 1: static_cast pentru numere și enumerări
#include <print>
enum class Luna { ianuarie = 1, februarie, martie };
int main() {
int suma = 27;
int numar = 4;
double media = static_cast<double>(suma) / numar;
std::println("Media: {}", media);
std::println("Partea întreagă: {}", static_cast<int>(media));
Luna l = static_cast<Luna>(3);
std::println("Luna 3 este martie: {}", l == Luna::martie);
}
Rezultat
Media: 6.75
Partea întreagă: 6
Luna 3 este martie: true
Exemplul 2: dynamic_cast verifică tipul real
Primul obiect este un Student, deci conversia reușește. Al doilea este doar o Persoana: varianta cu pointer dă nullptr, iar cea cu referință aruncă std::bad_cast.
#include <print>
#include <string>
#include <typeinfo>
struct Persoana {
std::string nume;
virtual ~Persoana() = default;
};
struct Student : Persoana {
int an = 2;
};
void verifica(Persoana* p) {
if (auto* s = dynamic_cast<Student*>(p)) {
std::println("{} este student în anul {}", s->nume, s->an);
} else {
std::println("{} nu este student", p->nume);
}
}
int main() {
Student ana;
ana.nume = "Ana";
Persoana mihai;
mihai.nume = "Mihai";
verifica(&ana);
verifica(&mihai);
try {
Student& s = dynamic_cast<Student&>(mihai);
std::println("an {}", s.an);
} catch (const std::bad_cast&) {
std::println("Conversia referinței a eșuat: std::bad_cast");
}
}
Rezultat
Ana este student în anul 2
Mihai nu este student
Conversia referinței a eșuat: std::bad_cast
Exemplul 3: const_cast și reinterpret_cast
const_cast permite apelul unei funcții vechi care nu modifică textul, dar nu cere const. reinterpret_cast la unsigned char* permite citirea octeților unui număr (aici ordinea este little-endian, ca pe Apple M și pe procesoarele Intel/AMD).
#include <cstdint>
#include <print>
int lungime_veche(char* text) { // funcție veche, fără const
int n = 0;
while (text[n] != '\0') ++n;
return n;
}
int main() {
const char* mesaj = "Salut";
std::println("Lungime: {}", lungime_veche(const_cast<char*>(mesaj)));
std::uint32_t numar = 0x0A0B0C0D;
auto* octeti = reinterpret_cast<unsigned char*>(&numar);
for (int i = 0; i < 4; ++i) {
std::print("{:02X} ", octeti[i]);
}
std::println("");
}
Rezultat
Lungime: 5
0D 0C 0B 0A
Greșeli frecvente
- Folosești
const_castca să modifici un obiect declarat inițialconst(const int x = 5;). Este comportament nedefinit;const_caste sigur doar dacă obiectul original nu eraconst. - Folosești
static_castîn loc dedynamic_castpentru a coborî în ierarhie fără să fii sigur de tip. Dacă obiectul nu este de tipul cerut, accesul ulterior este comportament nedefinit. - Folosești
dynamic_castpe o clasă fără nicio funcție virtuală. Nu se compilează: tipul trebuie să fie polimorfic.
Comenzi înrudite
virtual: Marchează o metodă care poate fi suprascrisă în clasele derivate; apelul printr-un pointer sau o referință la bază alege varianta tipului real.typeid: Dă informații despre tipul unei expresii la rulare; pentru clase cu funcții virtuale arată tipul real al obiectului.const: Marchează o valoare care nu mai poate fi modificată după inițializare; compilatorul oprește orice încercare de schimbare.pointeri (*, &): Un pointer este o variabilă care ține adresa altei variabile; prin el poți citi și modifica valoarea de la acea adresă.std::bit_cast: Reinterpretează biții unui obiect ca alt tip de aceeași mărime, în mod sigur (de exemplu biții unui float ca uint32_t).