C++四种强制类型转换
在C++语言中新增了四个关键字static_cast、const_cast、reinterpret_cast和dynamic_cast。新类型的强制转换可以提供更好的控制强制转换过程。
static_cast
static_cast用于将一种数据类型强制转换为另一种数据类型。
int a = 7; int b = 3; double result = static_cast<double>(a) / static_cast<double>(b);
可以使用static_cast找回存在于void*指针中的值
double a = 7; void* p = &a; double* dp = static_cast<double*>(p);
它主要有如下几种用法:
(1)用于类层次结构中基类和派生类之间指针或引用的转换
进行上行转换(把派生类的指针或引用转换成基类表示)是安全的
进行下行转换(把基类的指针或引用转换为派生类表示),由于没有动态类型检查,所以是不安全的
(2)用于基本数据类型之间的转换,如把int转换成char。这种转换的安全也要开发人员来保证
(3)把空指针转换成目标类型的空指针
(4)把任何类型的表达式转换为void类型
注意:static_cast不能转换掉expression的const、volitale或者__unaligned属性。
const_cast
const_cast用于强制去掉不能被修改的常数特性,但需要特别注意的是const_cast不是用于去除变量的常量性,而是去除指向常数对象的指针或引用的常量性,其去除常量性的对象必须为指针或引用。
用法:const_cast<type_id> (expression)
该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
常量指针被转化成非常量指针,并且仍然指向原来的对象;
常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。
const double a = 7; const double* p = &a; double* q = const_cast<double*>(p); *q = 20; //通过q写值是未定义的行为
reinterpret_cast
在C++语言中,reinterpret_cast主要有三种强制转换用途:改变指针或引用的类型、将指针或引用转换为一个足够长度的整形、将整型转换为指针或引用类型。
用法:reinterpret_cast<type_id> (expression)
type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。
它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,在把该整数转换成原类型的指针,还可以得到原先的指针值)。
在使用reinterpret_cast强制转换过程仅仅只是比特位的拷贝,因此在使用过程中需要特别谨慎!
dynamic_cast
用法:dynamic_cast<type_id> (expression)
(1)其他三种都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查。
(2)不能用于内置的基本数据类型的强制转换。
(3)dynamic_cast转换如果成功的话返回的是指向类的指针或引用,转换失败的话则会返回NULL。
(4)使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过。
基类中需要检测有虚函数的原因:类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义。
只有定义了虚函数的类才有虚函数表。
(5)在类的转换时,在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
向上转换,即为子类指针转换为父类指针(一般不会出问题);向下转换,即将父类指针转换为子类指针。
向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。
在C++中,编译期的类型转换有可能会在运行时出现错误,特别是涉及到类对象的指针或引用操作时,更容易产生错误。Dynamic_cast操作符则可以在运行期对可能产生问题的类型转换进行测试。
1 #include <iostream> 2 #include <string> 3 #include <vector> 4 using namespace std; 5 6 class Base{ 7 8 public: 9 Base() :str(nullptr){} 10 Base(string s) :str(s){} 11 virtual void print() 12 { 13 cout << str << " "; 14 } 15 private: 16 string str; 17 }; 18 19 class Derived:public Base 20 21 { 22 public: 23 Derived(){} 24 Derived(string s,int i) :Base(s),ival(i){} 25 void print() 26 { 27 Base::print(); 28 cout << ival << endl; 29 } 30 void print_ival() 31 { 32 cout << "仅输出ival的值:" << ival << endl; 33 } 34 private: 35 int ival; 36 }; 37 38 39 int main() 40 { 41 Base base("aaa"); 42 Derived de("xxx", 111); 43 //指针dynamic_cast 44 Base* pb = &de; 45 if (Derived* pd = dynamic_cast<Derived*>(pb)) 46 { 47 pd->print_ival(); 48 } 49 else 50 { 51 //转换失败返回空指针 52 cout << "type error..." << endl; 53 } 54 //引用dynamic_cast 55 Base& rf = de; 56 try 57 { 58 Derived& d = dynamic_cast<Derived&>(rf); 59 d.print_ival(); 60 } 61 catch (const std::bad_cast& ex) 62 { 63 //转换失败,抛出std::bad_cast异常 64 cout << ex.what(); 65 } 66 system("pause"); 67 }