Típus átalakítás

(toc)


      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<iostream>


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
<< padd->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 <iostream>


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_cast<int>(d); // d átalakítása int-re





     cout
<< "d = " << d
<< "\nx = " << x
<< endl;


    


     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<DerivedClass*>(basePtr);


     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<iostream>


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<ConstCastTest*>(this)->number--;


     cout
<< number;


}





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<ConstCastTest*>(this)->number-- utasítás ezt mégis lehetővé teszi. A this egy ConstCastTest típusú konstans mutató, mely konstans mivoltát a const_cast ideiglenesen feloldja és ezért módosítani
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_cast<int&>(ref)=7;


cout << "\ni = " << i;





A const_cast operátor konstans paraméter átadására is
használható nem-konstans paramétert váró függvénynek.





#include <iostream>


using namespace std;





void print (char *
str){ cout << str << endl;}





int main ()


{


     const char * c = "Konstans sor";


     print
( const_cast<char
*> (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 <iostream>


using std::cout;


#include <queue>





int main()


{


     int x = 160;


     int *ptr = &x;


    


     cout
<< *reinterpret_cast<char*>(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 <iostream>


using std::cout;


using std::endl;


#include <typeinfo>





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();


     cout
<< "A(z) " << dataType
<< " típusú adatok közül a legnagyobb:
"
;


     return max;


}





int main()


{


     int a = 8, b = 88, c = 22;


     double d = 95.96, e = 78.59, f = 83.99;


    


     cout
<< maximum(a, b, c) << endl;


     cout
<< maximum(d, e, f) << endl;


    


     return 0;


}





A kimenet:


A(z) i típusú adatok közül a
legnagyobb: 88


A(z) d típusú adatok közül a
legnagyobb: 95.96





A typeid használatához szükséged alkalmazni a <typeinfo> headert. A const char* dataType
= typeid(T).name();
utasítás az, amelyik visszatéríti a T aktuális típusának nevét. A typeid egy operátor, amely egy referenciát
térít vissza egy
type_info objektumról, amely egy adattípust képvisel. A typeid-t nem ajánlott switch-ben használni. Helyette inkább
használjunk virtuális
függvényeket
.





A dynamic_cast operátor olyan típus átalakításokra jó, amely a
program során történik és a fordító nem észlelheti. Általában downcasting-re
használják a programozók, azaz amikor az alaposztály objektumát lekonvertálják
egy derivált osztály objektumává. Ezt csakis mutatókkal vagy referenciákkal
lehet használni. Az RTTI olyan öröklési hierarchiákban játszik szerepet, amely
rendelkezik a polimorfizmussal.





#include <iostream>


using std::cout;


using std::endl;


const double PI =
3.14159;





class Shape


{


     public:


           virtual double area()
const { return
0.0; }


};





class Circle : public
Shape


{


     public:


           Circle(int r = 1) { radius = r; }


           virtual double area()
const { return
PI * radius * radius; }


     protected:


           int radius;


};





class Cylinder : public
Circle


{


     public:


           Cylinder(int h = 1) { height = h; }


           virtual double area()
const { return
2 * PI * radius * height + 2 * Circle::area(); }


     private:


           int height;


};





void outputShapeArea(const
Shape*);





int main()


{


     Circle
circle;


     Cylinder
cylinder;


     Shape
*ptr = 0;


     outputShapeArea(&circle);       //a kör területe


     outputShapeArea(&cylinder);     //a henger
területe


     outputShapeArea(ptr);
          //a
test területe


     return 0;


}





void outputShapeArea(const
Shape* shapePtr)


{


     const Circle *circlePtr;


     const Cylinder *cylinderPtr;


    


     cylinderPtr
= dynamic_cast<const
Cylinder*>(shapePtr); //Shape->Cylinder


    


     if(cylinderPtr != 0) //ha át lehetett alakítani Cylinderbe


           cout
<< "A henger területe: "
<< shapePtr->area();


     else


     {


           circlePtr
= dynamic_cast<const
Circle*>(shapePtr); //Shape->Circle


           if(circlePtr != 0) //ha át
lehetett alakítani Circlebe


                cout
<< "A kör területe: "
<< circlePtr->area();


           else


                cout
<< "Nem kör és nem henger.";


     }


     cout
<< endl;


}





A kimenet:


A kör területe: 3.14159


A henger területe: 12.5664


Nem kör és nem henger.





A program a Shape ősosztályt használja, mely rendelkezik
egy virtuális függvénnyel, egy
Circle
derivált osztállyal. A
Circle-nek
is van egy derivált osztálya, a
Cylinder. Mindkét derivált osztály felülírja az area virtuális függvényt. A main függvényben
deklarálva van egy-egy objektum a derivált osztályokból és egy mutató az
ősosztályból, amely nullával van inicializálva. Az
outputShapeArea függvény paramétere is egy
ősosztály mutató, de ennek ellenére a main-ben derivált mutatókkal is meg van
hívva. Ezt a fordító nem veszi észre, ő csak azt látja, hogy a típus rendben
van. Ahhoz, hogy a program működjön is, a
shapePtr mutatót downcasting-olni kell a derivált
mutatókra a
dynamic_cast
segítségével. Ennek eredményeképp a
cylinderPtr megkapja a shapePtr címét ha az const Cylinder* típus, különben zéró értéket vesz fel. Ha a kapott érték nem zéró, akkor
használható az
area()
függvény. Ugyanez az eljárás a másik típuskonverzió esetében is.





Explicit konstruktorok





     
Az Overloading
című bejegyzésben bebizonyosodott, hogy bármilyen konstruktor, melynek van egy
paramétere, használható implicit átalakító operátorként. Például egy
char-t átalakíthat osztály típussá. Az
átalakítás automatikusan történik, nem kell cast-okat használni. Bizonyos
esetekben azonban az ilyen művelet hibákat eredményezhet. Az alábbi programban
az
Array osztály konstruktora
olyan objektumot alkot, mely egy egydimenziós tömböt állít elő a paraméternek
megadott elemszám alapján.





array.h


#ifndef ARRAY_H


#define ARRAY_H


#include <iostream>


using std::ostream;





class Array


{


     friend ostream &operator<<(ostream&,
const Array&);


     public:


           Array(int = 10);


           ~Array();


     private:


           int size;


           int *ptr;


};


#endif





array.cpp


#include <iostream>


using std::cout;


using std::ostream;


#include <cassert>


#include "array.h"





Array::Array(int
arraySize)


{


     size
= (arraySize > 0 ? arraySize : 0);


     cout
<< "Konstruktor: "<<
size;


     ptr =
new int[size];


     assert(ptr
!= 0);


     for(int i = 0; i <
size; i++)


           ptr[i]
= 0;


}





Array::~Array() { delete
[] ptr; }





ostream &operator<<(ostream
&output, const Array&a)


{


     int i;


     for(i = 0; i < a.size; i++)


     output
<< a.ptr[i] << ' ';


     return output;


}





test_array.cpp


#include <iostream>


using std::cout;


#include "array.h"





void outputArray(const
Array&);





int main()


{


     Array
integers(7);


     outputArray(integers);


     outputArray(15);


     return 0;


}





void outputArray(const
Array &arrayToOutput)


{


     cout
<< "\nA tömb tartalma:\n"
<< arrayToOutput << "\n\n";


}





A kimenet:


Konstruktor: 7


A tömb tartalma:


0 0 0 0 0 0 0





Konstruktor: 15


A tömb tartalma:


0 0 0 0 0 0 0 0 0 0 0 0 0 0
0





Az Array osztály int paraméterű
konstruktorát átalakító operátorként is lehet használni,
int -> Array átalakításokra. A kiírásra z outputArray() függvényt használtuk, melynek paramétere const Array referencia. A főprogramban az integers egy Array típusú objektum, melynek deklarálásakor
azonnal lefut a konstruktor. Az
outputArray(integers) utasítás csupán kiírja a tömb tartalmát a felhasználva a << operátort túlterhelő függvényt. Az outputArray(15) utasítás egész típussal hívja meg az outputArray() függvényt, ami nem int típusú paramétert vár, ezért átalakítja azt Array típussá. Ez egy olyan eset, amikor a
konstruktort átalakító operátorként használtuk, és ez sokszor bezavarhat a
program logikájába. A C++ az ilyen esetekre tartja fent az
explicit kulcsszót, amelyet ha a konstruktor
prototípusa elé írunk az osztály definíciójában, akkor kizárja annak implicit
átalakító viselkedését. Ha a fenti programban átjavítjuk a definíciót
explicit Array(int = 10)-re, akkor a fordító nem fogja engedni az outputArray(15) utasítás használatát. Helyette az outputArray(Array(15)) lesz a helyes.





Mutable tagváltozók





     
A
mutable kulcsszó egy
alternatíva a
const_cast-ra, mellyel
módosítani lehet a tagváltozókat a
const tagfüggvényekben. Egy mutable tagváltozó változtatható marad a const tagfüggvényekben és const
objektumokban is. A
const_cast és a mutable különböző
kontextusban teszik lehetővé a változtatást. Egy olyan
const objektum esetén, melynek egyetlen mutable tagváltozója sincs, a const_cast operátort mindig alkalmazni kell
valahányszor változtatni szeretnénk egy tagváltozón. Ez a mechanizmus
jelentősen csökkenti az olyan tagváltozók véletlen módosítását, amelyek amúgy
módosíthatatlanok. Az olyan műveletek, amelyek igénybe veszik a
const_cast operátort általában el vannak rejtve a
tagfüggvényekben.





#include <iostream>


using std::cout;





class TestMutable


{


     public:


           TestMutable(int v = 0) {value = v;}


           void modifyValue() const
{value++;}


           int getValue() const
{return value;}


     private:


           mutable int value;


};





int main()


{


     const TestMutable t(99);


     cout
<< "Kezdeti érték: "
<< t.getValue();


     t.modifyValue();
//módosítja a mutable változót


     cout
<< "\nMódosított érték: "
<< t.getValue();


     return 0;


}





A kimenet:


Kezdeti érték: 99


Módosított érték: 100





A TestMutable osztály egy konstruktort, két const tagfüggvényt és egy mutable tagváltozót tartalmaz. A modifyValue tagfüggvény az amelyik módosítja a
tagváltozót. Normális esetben a const tagfüggvények nem kéne tudják módosítani
a tagváltozókat, hacsak az objektum ami felett dolgozik nincs a
const_cast operátor hatása alatt. Mivel a value tagváltozó mutable, a const tagfüggvény módosítani tudja annak értékét 99-ről 100-ra.



Find Out
Related Post



Ikuti AltairGate.com pada Aplikasi GOOGLE NEWS : FOLLOW (Dapatkan Berita Terupdate tentang Dunia Pendidikan dan Hiburan). Klik tanda  (bintang) pada aplikasi GOOGLE NEWS.

Top Post Ad

Below Post Ad

s