C++类型转换
旧式转型 C 风格的强制类型:
TYPE b = (TYPE) a
例如:
int i = 48; char c = (char) i;
新式转型 C++ 风格的类型转换提供了 4 种类型转换操作符来应对不同场合的应用。
TYPE b = 类型操作符 ( a )
类型操作符 = static_cast | reinterpreter_cast | dynamic_cast | const_cast
static_cast
静态类型转换(斯文的劝导,温柔的转换),类似于 C 语言中的隐式转换,如 int 转换成 char 。
主要用法:
用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。上行指针或引用(派生类到基类)转换安全,下行(基类到派生类)转换不安全。
用于基本数据类型之间的转换,如把 int 转换成 char ,把 int 转换成 enum 。这种转换的安全性也要开发人员来保证。
把空指针转换成目标类型的空指针。
把任何类型的表达式转换成 void 类型。
#include <iostream> using namespace std; class Animal { public: virtual void cry() = 0; }; class Cat :public Animal { public: void cry() { cout << "喵喵瞄" << endl; } }; class Dog :public Animal { public: void cry() { cout << "汪汪汪" << endl; } };
用法一:父子类之间的类型转换
Dog* dog1 = new Dog(); Animal* a1 = static_cast<Animal*>(dog1); //子类的指针转型到父类指针 Dog* dog1_1 = static_cast<Dog*>(a1); //父类的指针转型到子类的指针 //父子到子类,有风险,虽然下面这句不会报错,但是狗类转换成猫类是完全错误的做法 Cat* cat1 = static_cast<Cat*>(a1); Dog dog2; Animal& a2 = static_cast<Animal&>(dog2); //子类的引用转型到父类的引用 Dog& dog2_2 = static_cast<Dog&>(a2); //父类到子类引用
用法二:基本类型的转换
int kk = 234; char cc = static_cast<char>(kk);
用法三:把空指针转换成目标类型的空指针
int* p = static_cast<int*>(NULL); Dog* dp = static_cast<Dog*>(NULL);
用法四:把任何类型的表达式转换成 void 类型
int* pi = new int[10]; void* vp = static_cast<void*>(pi);
reinterpret_cast
重新解释类型(挂羊头,卖狗肉))不同类型间的互转,数值与指针间的互转。
用法: TYPE b = reinterpret_cast ( a )
TYPE 必须是一个指针、引用、算术类型、函数指针
忠告: 滥用 reinterpret_cast 运算符可能很容易带来风险。 除非所需转换本身是低级别的,否则应使用其他强制转换运算符之一。
#include <iostream> using namespace std; class Animal { public: void cry() { cout << "动物叫" << endl; } }; class Cat :public Animal { public: void cry() { cout << "喵喵瞄" << endl; } }; class Dog :public Animal { public: void cry() { cout << "汪汪汪" << endl; } };
用法一:数值与指针之间的转换
int* p = reinterpret_cast<int*>(0x99999); int val = reinterpret_cast<int>(p);
用法二:不同类型指针和引用之间的转换
Dog dog1; Animal* a1 = &dog1; a1->cry(); //动物叫 Dog* dog1_p = reinterpret_cast<Dog*>(a1); Dog* dog2_p = static_cast<Dog*>(a1); //如果能用static_cast ,static_cast 优先 dog1_p->cry(); //汪汪汪 dog2_p->cry(); //汪汪汪 //Cat* cat1_p = static_cast<Cat*>(a1); //输出喵喵喵 //Cat* cat2_p = static_cast<Cat*>(dog1_p); //报错,不同类型指针转换不能使用static_cast Cat* cat2_p = reinterpret_cast<Cat*>(dog1_p); //但是这个强制转换不会报错 cat2_p->cry(); //喵喵喵 Animal& a2 = dog1; Dog& dog3 = reinterpret_cast<Dog&>(a2);//引用强转用法
dynamic_cast
动态类型转换
将一个基类对象指针 cast 到继承类指针,dynamic_cast 会根据基类指针是否真正指向继承类指针来做相应处理。失败返回 null ,成功返回正常 cast 后的对象指针。
将一个基类对象引用 cast 继承类对象,dynamic_cast 会根据基类对象是否真正属于继承类来做相应处理。失败抛出异常 bad_cast 。
#include <iostream> using namespace std; class Animal { public: virtual void cry() = 0; }; class Cat :public Animal { public: void cry() { cout << "喵喵瞄" << endl; } void play() { cout << "爬爬树"<<endl; } }; class Dog :public Animal { public: void cry() { cout << "汪汪汪" << endl; } void play() { cout << "溜达溜达" << endl; } };
用法一:指针类型转换
void animalPlay(Animal* animal) { animal->cry(); Dog* pDog = dynamic_cast<Dog*>(animal); if (pDog) { pDog->play(); } else { //pDog == NULL cout << "不是狗,别骗我!" << endl; } Cat* pCat = dynamic_cast<Cat*>(animal); if (pCat) { pCat->play(); } else { //pDog == NULL cout << "不是猫,别骗我!" << endl; } } int main() { Dog* dog1 = new Dog(); Animal* a1 = dog1; animalPlay(a1); cout << endl; Cat* cat1 = new Cat(); Animal* a2 = cat1; animalPlay(a2); return 0; }
用法二:引用类型转换
void animalPlay(Animal& animal) { animal.cry(); try { Dog& pDog = dynamic_cast<Dog&>(animal); pDog.play(); } catch (std::bad_cast bc) { cout << "不是狗,那应该是猫" << endl; } try { Cat& pCat = dynamic_cast<Cat&>(animal); pCat.play(); } catch (std::bad_cast bc) { cout << "不是猫,那应该是上面的狗" << endl; } } int main() { Dog* dog1 = new Dog(); Dog dog2; animalPlay(dog2); cout << endl; Cat* cat1 = new Cat(); Cat cat2; animalPlay(cat2); return 0; }
const_cast
去掉 const 属性。(仅针对于指针和引用)
#include <iostream> using namespace std; void demo(const char* p) { //对指针去掉cost 重新赋值 char* p1 = const_cast<char *>(p); p1[0] = 'A'; //直接去掉const修改 const_cast<char*>(p)[1] = 'B'; cout << p << endl; } void demo(const int p) { int q = p; //const_cast<int>(p) = 888;//报错,不能对非指针和引用进行const 转换 cout << p << endl; } int main(void) { //字符串数组 //char p[] = "12345678"; //demo(p); //合情合理 //常量字符串不能去掉const 修改 //警告: 在去掉常量限定符之前,保证指针所指向的内存能够修改,不能修改则会引起异常。 const char* cp = "987654321"; demo(cp); system("pause"); return 0; }
类型转换使用建议
1)static_cast 静态类型转换,编译的时 c++ 编译器会做编译时的类型检查(隐式转换)。基本类型转换,父子类之间合理转换。
2)若不同类型之间,进行强制类型转换,用 reinterpret_cast<>() 进行重新解释。
注意: C 语言中能隐式类型转换的,在 c++ 中可用 static_cast<>() 进行类型转换,因 c++ 编译器在编译检查一般都能通过;C 语言中不能隐式类型转换的,在 c++ 中可以用 reinterpret_cast<>() 进行强制类型解释。
总结: static_cast<>() 和 reinterpret_cast<>() 基本上把C语言中的强制类型转换给覆盖,注意 reinterpret_cast<>() 很难保证移植性。
3)dynamic_cast<>() ,动态类型转换,安全的虚基类和子类之间转换,运行时类型检查。
4)const_cast<>() ,去除变量的只读属性。
最后的忠告: 程序员必须清楚的知道 —— 要转的变量,类型转换前是什么类型,类型转换后是什么类型,转换后有什么后果。
C ++大牛建议: 一般情况下,不建议进行类型转换,避免进行类型转换。