C++ casts: static_cast, dynamic_cast, const_cast, reinterpret_cast

1. c cast and c++ cast

 C language mandatory type conversion is mainly used for conversion between basic data types. The syntax is:

(type-id)expression // conversion format 1 

type -id(expression) // conversion format 2

In addition to the mandatory type conversion of C language, c++ also adds four new mandatory type conversions: static_cast, dynamic_cast, const_cast, reinterpret_cast, which are mainly used for coercive conversion between inheritance classes. The syntax is:

static_cast<new_type>      (expression)
dynamic_cast<new_type>     (expression) 
const_cast<new_type>       (expression) 
reinterpret_cast<new_type> (expression)

Remarks: new_type is the target data type, and expression is the original data type variable or expression.

In "Effective C++", C language casts are called old -style casts, and C++ casts are called new casts .

2. static_cast、dynamic_cast、const_cast、reinterpret_cast

  •  static_cast

static_cast is equivalent to the traditional cast in C language. This operator converts expression to new_type type, which is used to force implicit conversion, such as non-const object to const object, compile-time check, for non-polymorphic conversion , pointers and more can be converted, but there is no runtime type checking to guarantee the safety of the conversion . It mainly has the following uses:
① It is used for the conversion of pointers or references between the base class (parent class) and the derived class (subclass) in the class hierarchy.
It is safe to perform upcasting (converting a pointer or reference from a derived class to a base class representation) ;
Downcasting (converting a base class pointer or reference to a derived class representation) is unsafe because there is no dynamic type checking .
②It is used for conversion between basic data types, such as converting int to char, and converting int to enum. The security of this conversion should also be guaranteed by the developer.
③ Convert the null pointer to a null pointer of the target type.
④ Convert any type of expression to void type.
Note: static_cast cannot convert the const, volatile, or __unaligned attributes of expression.
 
Examples of basic type data conversion are as follows:
复制代码
char a = ' a ' ;
 int b = static_cast< char >(a); // Correct, convert char data to int data

double *c = new double;
void *d = static_cast<void*>(c);//正确,将double指针转换成void指针

int e = 10;
const int f = static_cast<const int>(e);//正确,将int型数据转换成const int型数据

const int g = 20;
int *h = static_cast<int*>(&g);//编译错误,static_cast不能转换掉g的const属性

复制代码
 
类上行和下行转换:
复制代码
if(Derived *dp = static_cast<Derived *>(bp)){//下行转换是不安全的
  //使用dp指向的Derived对象  
}
else{
  //使用bp指向的Base对象  
}

if(Base*bp = static_cast<Derived *>(dp)){//上行转换是安全的
  //使用bp指向的Derived对象  
}
else{
  //使用dp指向的Base对象  
}
复制代码

 

  • dynamic_cast

dynamic_cast<type*>(e)
dynamic_cast<type&>(e)
dynamic_cast<type&&>(e)

  type必须是一个类类型,在第一种形式中,type必须是一个有效的指针,在第二种形式中,type必须是一个左值,在第三种形式中,type必须是一个右值。在上面所有形式中,e的类型必须符合以下三个条件中的任何一个:e的类型是是目标类型type的公有派生类、e的类型是目标type的共有基类或者e的类型就是目标type的的类型。如果一条dynamic_cast语句的转换目标是指针类型并且失败了,则结果为0。如果转换目标是引用类型并且失败了,则dynamic_cast运算符将抛出一个std::bad_cast异常(该异常定义在typeinfo标准库头文件中)。e也可以是一个空指针,结果是所需类型的空指针。

dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换(cross cast)。
在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;
在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。dynamic_cast是唯一无法由旧式语法执行的动作,也是唯一可能耗费重大运行成本的转型动作。
(1)指针类型
举例,Base为包含至少一个虚函数的基类,Derived是Base的共有派生类,如果有一个指向Base的指针bp,我们可以在运行时将它转换成指向Derived的指针,代码如下:
if(Derived *dp = dynamic_cast<Derived *>(bp)){
  //使用dp指向的Derived对象  
}
else{
  //使用bp指向的Base对象  
}

值得注意的是,在上述代码中,if语句中定义了dp,这样做的好处是可以在一个操作中同时完成类型转换和条件检查两项任务。

(2)引用类型

因为不存在所谓空引用,所以引用类型的dynamic_cast转换与指针类型不同,在引用转换失败时,会抛出std::bad_cast异常,该异常定义在头文件typeinfo中。

复制代码
void f(const Base &b){
 try{
   const Derived &d = dynamic_cast<const Base &>(b);  
   //使用b引用的Derived对象
 }
 catch(std::bad_cast){
   //处理类型转换失败的情况
 }
}
复制代码

 

  • const_cast

const_cast,用于修改类型的const或volatile属性。 

该运算符用来修改类型的const(唯一有此能力的C++-style转型操作符)或volatile属性。除了const 或volatile修饰之外, new_type和expression的类型是一样的。
①常量指针被转化成非常量的指针,并且仍然指向原来的对象;
②常量引用被转换成非常量的引用,并且仍然指向原来的对象;
③const_cast一般用于修改底指针。如const char *p形式。
 
举例转换如下:
复制代码
const int g = 20;
int *h = const_cast<int*>(&g);//去掉const常量const属性

const int g = 20;
int &h = const_cast<int &>(g);//去掉const引用const属性

 const char *g = "hello";
char *h = const_cast<char *>(g);//去掉const指针const属性
复制代码

 

  • reinterpret_cast

new_type必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)。

reinterpret_cast意图执行低级转型,实际动作(及结果)可能取决于编辑器,这也就表示它不可移植

  举一个错误使用reintepret_cast例子,将整数类型转换成函数指针后,vc++在执行过程中会报"...中的 0xxxxxxxxx 处有未经处理的异常: 0xC0000005: Access violation"错误:

复制代码
#include <iostream>
using namespace std;
int output(int p){
    cout << p <<endl;
  return 0;
}

typedef int (*test_func)(int );//定义函数指针test_func
int main(){
    int p = 10;
    test_func fun1 = output;
    fun1(p);//正确
    test_func fun2 = reinterpret_cast<test_func>(&p);
    fun2(p);//...处有未经处理的异常: 0xC0000005: Access violation
    return 0;
}
复制代码

IBM的C++指南、C++之父Bjarne Stroustrup的FAQ网页MSDN的Visual C++也都指出:错误的使用reinterpret_cast很容易导致程序的不安全,只有将转换后的类型值转换回到其原始类型,这样才是正确使用reinterpret_cast方式。

  MSDN中也提到了,实际中可将reinterpret_cast应用到哈希函数中,如下(64位系统中需将unsigned int修改为unsigned long):
复制代码
// expre_reinterpret_cast_Operator.cpp
// compile with: /EHsc
#include <iostream>

// Returns a hash code based on an address
unsigned short Hash( void *p ) {
   unsigned int val = reinterpret_cast<unsigned int>( p );
   return ( unsigned short )( val ^ (val >> 16));
}

using namespace std;
int main() {
   int a[20];
   for ( int i = 0; i < 20; i++ )
      cout << Hash( a + i ) << endl;
}
复制代码

 

   另外,static_cast和reinterpret_cast的区别主要在于多重继承,比如
 
复制代码
class A {
    public:
    int m_a;
};
 
class B {
    public:
    int m_b;
};
 
class C : public A, public B {};
复制代码
   那么对于以下代码:
  
C c;
printf("%p, %p, %p", &c, reinterpret_cast<B*>(&c), static_cast <B*>(&c));

 

   前两个的输出值是相同的,最后一个则会在原基础上偏移4个字节,这是因为static_cast计算了父子类指针转换的偏移量,并将之转换到正确的地址(c里面有m_a,m_b,转换为B*指针后指到m_b处),而reinterpret_cast却不会做这一层转换。
 因此, 你需要谨慎使用 reinterpret_cast。
 

3. c++强制转换注意事项

  • 新式转换较旧式转换更受欢迎。原因有二,一是新式转型较易辨别,能简化“找出类型系统在哪个地方被破坏”的过程;二是各转型动作的目标愈窄化,编译器愈能诊断出错误的运用。
  • 尽量少使用转型操作,尤其是dynamic_cast,耗时较高,会导致性能的下降,尽量使用其他方法替代。

 

参考资料:

a):http://en.cppreference.com/w/cpp/language/static_cast

b):http://en.cppreference.com/w/cpp/language/dynamic_cast

c):http://en.cppreference.com/w/cpp/language/const_cast

d):http://en.cppreference.com/w/cpp/language/reinterpret_cast

e):《Effective C++》条款27:尽量少做转型动作

f): 百度百科

g) 《C++ Primer》


https://www.cnblogs.com/chenyangchun/p/6795923.html

https://blog.csdn.net/ZDF0414/article/details/49156589

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325641341&siteId=291194637