有时候我们需要在表达式中显示地将对象强制转换为另一种类型参与运算,称作**强制类型转换(cast)。一个命名的强制类型的形式为 cast-name(expression)**,其中type是转换的目标而expression是要转换的值。
static_cast 任何具有明确定义的类型转换,且不包含底层const,都可以使用static_cast。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 int a = 9 ;int b = 8 ;cout << a / b << endl ;cout << static_cast<double >(a) / b <<endl ;const char * p = "helloworld" ;char * q = static_cast<char *>(p); *q = 'H' ; cout << q << endl ;char * const x = "aloha" ;char * y = static_cast<char *>(x); y = "hello" ; cout << x << endl ;cout << y << endl ;cout << static_cast<string >(x) << endl ;cout << static_cast<string >(y) << endl ;cout << static_cast<const string >(y) << endl ;
const_cast const_cast只能改变运算对象的底层const。对于将常量对象转换为非常量对象,称为去掉const性质 。如果对象本身不是常量,则获得写权限是合法的行为,反之对其进行写操作会产生未定义的后果。 const_cast接受的操作对象只能是指针、引用或者指向类类型对象的成员指针。 const_cast与static_cast对比
1 2 3 4 5 const char * sp;char *q = static_cast<char *>(sp); static_cast<string >(sp); const_cast<string >(sp); char * l = const_cast<char *> (sp);
使用const_cast获得常量的写操作权限
1 2 3 4 5 void write_const (const char * cp) { char * q = const_cast<char *> (cp); *q = 'H' ; }
该函数通过将指向常量的指针参数,去掉其底层const,尝试进行写操纵。 当cp指向真正的常量时,如下main函数
1 2 3 4 5 6 7 int main () { const char * sp = "helloworld" ; write_const(sp); return 0 ; }
编译通过,运行。触发segment fault:
1 2 > g++ main.cc -g -o main && ./main fish: Job 1, './main' terminated by signal SIGSEGV (Address boundary error)
若sp指向的是非常量
1 2 3 4 5 6 7 8 9 int main () { char arr[] = "helloworld" ; const char * sp = arr; write_const(sp); cout << sp << endl ; return 0 ; }
编译通过,运行,写入成功:
1 2 > g++ main.cc -g -o main && ./main Helloworld
如下程序通过去掉const特性修改string的内容:
1 2 3 4 5 6 7 8 9 10 11 12 int main (int argc, char **argv) { const string s = "Hello" ; const string & crs = s; string & rs = const_cast <string &>(crs); cout << s << ' ' << crs << ' ' << rs<<endl; rs = "world" ; cout << s << ' ' << crs << ' ' << rs<<endl; return 0 ; }
运行结果如下:
1 2 3 > g++ main.cc -g -o a && ./a Hello Hello Hello world world world
const_cast操作对象不是指针或引用时会编译出错:
1 2 3 4 5 6 7 8 int main (int argc, char **argv) { string s = "hello" ; const string cs = const_cast <const string>(s); return 0 ; }
reinterpret_cast reinterpret_cast通常为运算对象的位模式提供较低层次上的重新解释。
1 2 3 4 int arri[] = {0x6c6c6568 , 0x726f776f , 0x646c };char * p = reinterpret_cast<char *>(arri);cout << p << endl ;
运行结果为
1 2 > g++ main.cc -g -o main && ./main helloworld
dynamic_cast dynamic_cast运算符,用于将基类指针或引用安全转换为派生类的指针或引用。使用形式如下
dynamic_cast<type *>(e),e必须是一个有效的指针
dynamic_cast<type &>(e),e必须是一个左值
dynamic_cast<type &&>(e),e不能是左值
其中,type必须是一个类类型,并且通常情况下该类型应该含有虚函数。e的类型必须符合如下三个条件中任一一个:
e的类型是目标type的公有派生类
e的类型是目标typpe的公有基类
e的类型就说目标type的类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class base { public : base () { cout << " \n base constructor \n" ; } }; class derived : public base{ public : derived () { cout << " \n derived constructor \n" ; } }; int main () { base *obj = new derived; derived *OBJ = dynamic_cast <derived *>(obj); return 0 ; }
此种情况下,base类没有虚函数,编译器会提示错误信息
1 the operand of a runtime dynamic_cast must have a polymorphic class typeC/C++(698)
任一添加虚函数后,程序通过编译(note: 虚函数必须有定义,不能只声明)。
对于转换类型是指针和引用,当转换失败时的行为不同:若一条 dynamic_cast语句的转换目标是指针类型,则结果为0;若转换目标是引用类型,则dynamic_cast运算符抛出bad_cast异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class base { public : base () { cout << " \n base constructor \n" ; } virtual void foo () { } }; class derived : public base{ public : derived () { cout << " \n derived constructor \n" ; } }; int main () { base *obj = new derived; derived *OBJ = dynamic_cast <derived *>(obj); derived d; base &rb = d; try { derived &rd = dynamic_cast <derived &>(rb); } catch (const std::exception &e) { std::cerr << e.what () << '\n' ; } delete obj; return 0 ; }
上述例子可以运行成功。下面这个例子中的指针和引用转换失败:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 int main () { base *obj = new base; derived *OBJ = dynamic_cast <derived *>(obj); assert (OBJ == nullptr ); base b; base &rb = b; try { derived &rd = dynamic_cast <derived &>(rb); } catch (const std::exception &e) { std::cerr << e.what () << '\n' ; } delete obj; return 0 ; }
输出结果如下