Az adat típusának átalakítását egy másik típusra type-cast-nak nevezik. Két típusú átalakítás
lehetséges: az implicit és explicit átalakítás. Az implicit átalakításhoz nincs
szükség cast-re, mert az
átalakítás automatikusan megtörténik a másolásnál ha a cél memóriahelye
kompatibilis adattípust tárol.
short a=2000;
int b;
b=a;
Ebben a példában a short típusú változó int típussú változóvá alakult. A hasonló átalakítások
néha veszítenek az adatok pontosságából, de ezt a fordító jelzi. Nem csak az
alapvető adattípusokat lehet átalakítani, hanem az osztály típusú adatokat is.
class A {};
class B {
public: B (A a) {} };
A a;
B b=a;
A B osztály konstruktora egyetlen A típusú objektumot használ paraméternek, így B objektuma hasonló lesz A objektumával és az átalakítás lehetséges.
Az eltérő értelmezést igénylő átalakítások
explicit átalakítások kell legyenek és ezek kétféleképp is meghatározhatóak:
short a=2000;
int b;
b = (int) a;
b = int (a);
Ezt e két operátor bármilyen átalakításnál
használható, ide értve az osztály-osztály és mutató-osztály átalakítást. Habár
egy ilyen átalakítás szintaktikailag helyes, mégis hibát vagy redundáns
kimenetet eredményezhet.
#include
using namespace std;
class A {
float i,j;
};
class B {
int x,y;
public:
B
(int a, int b)
{ x=a; y=b; }
int result() { return
x+y;}
};
int main () {
A d;
B *
padd; //
padd egy B típusú mutató
padd
= (B*) &d; // padd az A típusú objektumra (d) mutat
cout
result(); // az A osztálynak nincs
is result() függvénye
// mégsem jelez hibát a fordító
return 0;
}
A fenti programban A és B
osztály nem kompatibilisek egymással. Ennek ellenére az A objektumát (d) át lehet konvertálni, hogy a B mutatója (padd) rá mutasson. A padd használhatatlanná válik, és a fordító ezt
nincs honnan lássa.
A static_cast operátor
A standard C++ alapvetően négy cast operátort tartalmaz: static_cast, const_cast, reinterpret_cast és dynamic_cast. Az újabbak kevésbé használatosak, már csak azért
is hogy nincsenek ennyire általánosítva. Az implicit átalakításhoz hasonlóan
itt sem lehet szintaxis hibát észlelni egy hibás átalakításnál, viszont a
fordítás során minden adattípus ellenőrzésre kerül. A static_cast operátor a
standard adattípusok közti átalakításra jó, mint például void* -> char* vagy int -> double és ezek fordítottjai.
#include
using std::cout;
using std::endl;
class BaseClass
{
public:
void f() const { cout
"Ősosztály\n"; }
};
class DerivedClass : public
BaseClass
{
public:
void f() const { cout
"Derivált osztály\n"; }
};
void test(BaseClass*);
int main()
{
double d = 8.22;
int x = static_castint>(d); // d átalakítása int-re
cout
"d = " "\nx = "
BaseClass
*basePtr = new DerivedClass; //memóriafoglalás
test(basePtr);
//egy globális függvény
delete basePtr; //memória
felszabadítás
return 0;
}
void test(BaseClass *basePtr)
{
DerivedClass
*derivedPtr; //derivalt osztály típusó mutató
//az ősosztály típusú mutatót átalakítjuk derivált típusú mutatóvá
derivedPtr
= static_cast
derivedPtr->f();
//az f a derivált osztályból fog lefutni
}
A kimenet:
d = 8.22
x = 8
Derivált osztály
A BaseClass *basePtr = new
DerivedClass utasítás
létrehoz egy BaseClass típusú mutatót és rögtön rá is irányítja egy DerivedClass típusú objektumra. Ezután a mutató mint
paraméter jut el a test
függvénybe, ahol értékét leadja egy DerivedClass típusú mutatónak. Ehhez a static_cast segítségével ő maga is át kell alakuljon DerivedClass típussá. Ezt a műveletet downcast-nak nevezik, mert felső osztálytípusból
alsó osztálytípusba történt az átalakítást. Ez általában veszélyes művelet,
mert a programozónak előbb biztosra kell tudnia, hogy az objektumok
kompatibilisek egymással, ebben az esetben például mindkét osztálynak
rendelkeznie kell az f()
függvénnyel.
virtuális függvényeket meghívó virtualViaPointer és virtualViaReference függvények esetén a
fordító nem tudja meghatározni, hogy milyen típusú lesz a baseClassPtr objektum, ami akár problémák a forrása is lehet.
A const_cast operátor
A const és volatile típusu adatok átalakítására jó. A
következő programban a const_cast egy osztály tagváltozóját alakítja át, egy const tagfüggvény révén, amely normális esetben
nem változtathatná meg az objektum felépítését.
#include
using std::cout;
class ConstCastTest
{
public:
void setNumber(int);
int getNumber() const;
void printNumber() const;
private:
int number;
};
void ConstCastTest::setNumber(int num) { number = num; }
int ConstCastTest::getNumber() const { return
number; }
void ConstCastTest::printNumber() const
{
cout
"\nprintNumber() = ";
//a number módosítás hibát adna, mert a függvény const
const_cast
cout
}
int main()
{
ConstCastTest
x;
x.setNumber(8);
cout
"getNumber() = " x.getNumber();
x.printNumber();
return 0;
}
A kimenet:
getNumber() = 8
printNumber() = 7
A ConstCastTest osztály három publikus tagfüggvényt és egy privát tagváltozót tartalmaz.
Két tagfüggvény konstans, ami azt jelenti, hogy nem változtathat semmit a
tagváltozón. A printNumber függvényben a const_cast
lehet a number értékét. A fordító
nem jelez hibát. A const_cast operátort nem lehet közvetlenül konstans változón használni, hanem
konstans mutatókkal vagy konstans referenciákkal működik, például:
int i = 8;
const int& ref =
i;
const_castint&>(ref)=7;
cout "\ni = "
A const_cast operátor konstans paraméter átadására is
használható nem-konstans paramétert váró függvénynek.
#include
using namespace std;
void print (char *
str){ cout
int main ()
{
const char * c = "Konstans sor";
( const_castchar
*> (c) );
return 0;
}
A reinterpret_cast
operátor
A nem standard átalakítások a reinterpret_cast operátorral történnek. Inkább különböző típusú
mutatók között végez átalakítást, a standard típusokkal nem működik, mint a double -> int.
#include
using std::cout;
#include
int main()
{
int x = 160;
int *ptr = &x;
cout
reinterpret_castchar*>(ptr);
return 0;
}
A kimenet:
á
A fenti programban a ptr mutató az x címével van inicializálva. Mindkettő int típus. A reinterpret_cast a mutatót char típussá alakítja. Ettől az x
értéke char-ként lesz értelmezve
és az eredmény az x
értékének ASCII kódja, ami éppen az á betű. Mivel a reinterpret_cast platform-függő, előfordulhat hogy egy-egy platformon másképp viselkedik.
Run-Time Type Information
(RTTI)
Az RTTI lehetővé teszi egy objektum típusának meghatározását a program
futása alatt. A következő példák a typeid és a dynamic_cast operátorokat mutatják be:
#include
using std::cout;
using std::endl;
#include
template class T>
T maximum(T value1, T value2, T value3)
{
T max
= value1;
if(value2 > value1) max = value2;
if(value3 > max) max = value3;
const char* dataType
= typeid(T).name();