7. Преобразуване на типове
В стандарта на C++ има четири операции за преобразуване на типовете. За предпочитане е те да се използват вместо старото преобразуване, включено в C и C++ - въпреки, че са по-малко мощни, те са по-конкретни, което дава възможност за по-точен контрол. Преобразуването в C е едно за всички случаи. Дали това е хубаво или лошо нещо, е въпрос на лично мнение.
static_cast
static_cast е за преобразуване на типа, когато проверката на типа се извършва по време на компилация. Извършва стандартни преобразувания. Например void* → char* и обратно. Извършването на неразрешено преобразуване е синтактична грешка. Неразрешено е преобразуването от константни в неконстантни типове, типове на указатели и псевдоними, в типове, които не са в отношение на открито наследяване, преобразуване в тип без конструктор или предефинирана операция1.
Пример:
#include <iostream> using std::cout; using std::endl; class BaseClass { public: void f () const { cout << “Base” << endl; } } ; class DerivedClass : public BaseClass { public: void f () const { cout << “Derived” << endl; } } ; void test (BaseClass *); void main () { double d = 8.22; int x = static_cast < int > (d); cout << “d = “ << d << endl << “x = “ << x << endl; BaseClass *basePtr = new DerivedClass; test (basePtr); delete basePtr; } void test (BaseClass *basePtr) { DerivedClass *derivedPtr; derivedPtr = static_cast <DerivedClass*> (basePtr); derivedPtr -> f (); }
извършва се понижаващо преобразуване( down cast ) на указател от базовия клас в указател на производния – което е опасно, но static_cast го позволява. Нищо не гарантира, че обектът в derivedPtr може да се използва като DerivedClass. От програмиста зависи да осигури тази гаранция. static_cast е по-несигурно, но по-бързо от dynamic_cast, защото по време на изпълнение не се проверява дали преходът е коректен.
const_cast
const_cast маха const или volatile чрез преобразуване. По този начин, една const стойност може да бъде използвана като обикновена, включително и да бъде променяна. Използва се когато дадена функция приема променлива от тип Т, но разполагаме с променлива от тип const T.
Променлива, която е декларирана константна (const int a = 10) може да бъде променяна по този начин, но поведението не е дефинирано по стандарт. Възможно е да се изведе съобщение за грешка.
Променлива, която е декларирана без const модификатор, в някой момент го е получила, а после е била взета с const_cast - може да бъде променяна без проблеми.
Пример за употреба на const_cast.
#include <iostream> using namespace std; void f(int* p) { cout << *p << endl; } int main(void) { const int a = 10; const int* b = &a; // f() очаква int*, не const int* // f(b); int* c = const_cast<int>(b); f(c); // *b е констнанта, следващият ред не е валиден. // *b = 20; // По стандарт не е дефинирано какво ще стане тук // *c = 30; int a1 = 40; const int* b1 = &a1; int* c1 = const_cast<int>(b1); // a1, това към което сочи c1, не е декларирана константна *c1 = 50; return 0; }
reinterpret_cast
reinterpret_cast се използва за нестандартни преобразувания. От един тип указател към друг. Не може да се използва за стандартни преобразувания. ( double → int ). Почти никога не се използва, защото възможностите, които предоставя са твърде непредвидими. Може да преобразува от указател към произволен клас, в указател към произволен друг. В почти всички случаи това е нещо лошо, по същите причини, поради които и със static_cast трябва да се внимава. Единствената безопасна употреба на резултата от reinterpret_cast е да се върне обратно в базовия тип.
Пример:
#include <iostream> using std::cout; using std::endl; void main() { int x = 120; int *ptr = &x; cout << reinterpret_cast< char* > ( ptr ) << endl; }
В случая преобразува int* → char*. Може да се използва преобразуване на указател в цяло число(друг указател, short, int) и обратно. Като цяло, това е опасно. Освен всичко друго една и съща програма с reinterpred_cast може да се изпълнява различно на различни платформи.