启
类型转换是我们经常遇到的问题,C-type的类型转换都很熟悉也很简单,但是C-type的显式类型转换几乎任何类型之间都可以转换,显得太"流氓",很难判断是否正确,是否安全。因此C++引入了四种全新的类型转换机制,static_cast、const_cast、reinterpret_cast、dynamic_cast,后两种过于复杂,了解的不好,待以后再做探讨。
static_cast
任何具有明确定义的类型转换,只要不包含底层const(见最下注释),都可以使用static_cast.
基本语法如下:
1 typename value = static_cast<typename>(expression);
例如:
1 double x = static_cast<double> (y);//y可以是多种类型
The result of static_cast<typename>(expression) belongs to one of the following value categories:
- If typename is an lvalue reference type or an rvalue reference to a function type, static_cast<Type>(expression) is an lvalue.
- If typename is an rvalue reference to an object type, static_cast<Type>(expression) is an xvalue.
- In all other cases, static_cast<Type>(expression) is a (prvalue)rvalue.
实际上,将大型算术类型转换给小型算术类型时很有用(如double转换为int),使用static_cast告诉编译器,我知道会损失精度但是并不在乎,这样编译器就不会发出警告。
更让人高兴的是,static_cast对于编译器无法自动执行的类型转换提供了很好的支持。
例如:
1 double somevalue = 3.14; 2 void *p = &somevalue;//正确:任何非const对象的地址都能存入void*,但是不能通过p修改somevalue 3 double *pd = static_cast<double*>(p);//正确
经过测试,*p和*pd都是指向somevalue的。
const_cast
const_cast只能改变运算对象的底层const.
语法规则如下:
1 type something = const_cast<type>(expression);
1 const char* pc; 2 char *p = const_cast<char*>(pc);
要注意的是,这种转换只能更改引用或者指针,也就是说下面这种写法是报错的。
1 const int a = 100; 2 int b = const_cast<int>(a);//error: invalid use of const_cast with type 'int', which is not a pointer, reference, nor a pointer-to-data-member type
对于将常量对象转换成非常量对象的行为,我们称其为“去掉const性质”(cast away the const),一旦失去了某个对象的const性质,编译器将不再阻止我们对该对象进行修改但是一定要注意的是:如果对象本身是一个常量,将常量转换为非常量后,使用转换后的非常量修改值是未定义行为(undefined behavior),虽然编译器不会报错也不会waring,但是不同的编译器对这种行为有不同的判断,因此这是一种非常危险的行为。但如果对象本身不是一个常量,在cast away the const 后,修改其内容是合法的。
以下摘自IBM Knowledge Center:
1 #include <iostream> 2 using namespace std; 3 4 void f(int* p) { 5 cout << *p << endl; 6 } 7 8 int main(void) { 9 const int a = 10; 10 const int* b = &a; 11 12 // Function f() expects int*, not const int* 13 // f(b); 14 int* c = const_cast<int*>(b); 15 f(c); 16 17 // Lvalue is const 18 // *b = 20; 19 20 // Undefined behavior 21 // *c = 30; 22 23 int a1 = 40; 24 const int* b1 = &a1; 25 int* c1 = const_cast<int*>(b1);//a1 is not a const,so we can use c1 to change the value of al 26 27 // Integer a1, the object referred to by c1, has 28 // not been declared const 29 *c1 = 50; 30 31 return 0; 32 }
以下是官方解释:
- The compiler does not allow the function call f(b). Function f() expects a pointer to an int, not a const int.//编译器不允许调用f(b)因为f()的参数为int*不是const int*,此时用const_cast可以去掉const后传递进去
- Consequently the compiler does allow the function call f(c).//c是转换类型得到的,可以调用f(int*)
- The compiler would not allow the assignment *b = 20 because b points to an object of type const int. The compiler does allow the *c = 30, but the behavior of this statement is undefined //不允许*b = 20,这是const_cast规定的,但是实际上不会报错,这是一种未定义行为,不同的编译器有不同的处理结果
- However, if you cast away the constness of an object that has not been explicitly declared as const, you can modify it safely. In the above example, the object //不过如果原对象本身是非const的,通过c1修改a1是完全安全的
———————————————————————————————————————————————————————————————————————————————
PS:底层const和顶层const的定义如下:
As we’ve seen, a pointer is an object that can point to a different object. As a result,we can talk independently about whether a pointer is const and whether the objectsto which it can point are const. We use the term top-level const to indicate that thepointer itself is a const. When a pointer can point to a const object, we refer to that const as a low-level const。
指针本身是const,使用术语顶层const。
指针指向的对象是const,使用术语底层const。