C++:类型转换——static_cast和const_cast

  类型转换是我们经常遇到的问题,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。

 

posted @ 2015-03-22 17:26  SixDayCoder  阅读(2343)  评论(0编辑  收藏  举报