C++--强制类型转换static_cast、dynamic_cast、const_cast、reinterpret_cast

     C++中的强制类型转换主要有4种static_cast、dynamic_cast、const_cast、reinterpret_cast

    1.static_cast

          静态类型转换,使用形式如下:

static_cast<new_type> (expresion);

        其中new_type为目标类型,expresion为原始数据类型变量或表达式。

         static_cast用来强迫隐式转换,如将non-const对象转为const对象,编译时进行检查,但没有运行时类型检查来保证转换的安全性。主要有以下几种用法:

  • 用于类层次结构中基类和派生类之间指针或引用的转换。此时,进行上行转换(即把派生类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,是不安全的
  • 用于基本数据类型之间的转换,如把int转换为char,int转换为enum,这种转换的安全性需要开发人员来保证。
  • 把空指针转换成目标类型的指针(这是极其不安全的)
  • 把任何类型的表达式转换成void类型
  • static_cast无法转换掉expression的const,volatile,__unaligned属性

示例如下:

char a = 'a';
int b = static_cast<int>(a);//正确,将char型数据转换成int型数据

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属性

2.dynamic_cast

     动态类型转换,形式如下:

dynamic_cast<type>(expression);

   dynamic_cast会在运行时检查类型转换是否合法,在进行上行转换时,dynamic_cast和static_cast没有区别,都是安全的;下行转换时,dynamic_cast会检查转换的类型,比static_cast安全。

  •  不能用于内置的基本数据类型的强制转换
  • dynamic_cast转换如果成功返回的是指向类型的指针或引用。转换目标类型是指针且失败,则返回NULL;如果转换模板类型是引用且失败,则抛出std::bad_cast异常
  • 转换类指针时,基类中一定要有虚函数

     为什么基类中一定要有虚函数?dynamic_cast转换是在运行时进行转换,运行时转换就需要知道类对象的信息(继承关系等)。虚函数表可以帮助在运行时获取这些信息。在C++对象模型中,对象实例最前面的就是虚函数表指针,通过这个指针可以获取到该类对象的所有虚函数,包括父类的,因为派生类会继承基类的虚函数表,在转换时可以用来判断对象有无继承关系。

示例1:继承中的转换

上行转换中,dyanmic_cast与static_cast一样,是安全的。在下行转换时

class A { virtual void f(){}; };
class B : public A{ };
void main()
{
     A* pA = new B;
     B* pB = dynamic_cast<B*>(pA); 
}

     类A中必须要有虚函数,因为dynamic_cast运行时类型检查需要运行时类型信息,这些信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表

示例2:void*转换

     有些时候,需要将指针转换为void*,然后在合适的时候重新将void*转换为目标类型指针

class A { virtual void f(){} };
int main()
{
     A *pA = new A;
     void *pV = dynamic_cast<void *>(pA); 
}

示例3:菱形继承中的上行转换

class A { virtual void f() {}; };
class B :public A { void f() {}; };
class C :public A { void f() {}; };
class D :public B, public C { void f() {}; };

     继承关系为:

      此时:D对象指针能否安全的转换为A类型的指针?

void main()
{
    D *pD = new D;
    A *pA = dynamic_cast<A *>(pD); // pA = NULL
}

       结果得到一个空指针。这是因为B和C都实现了虚函数,导致在进行转换时,无法选择一条转换路径。一种方法是:指定一条转换路径

void main()
{
    D *pD = new D;
    B *pB = dynamic_cast<B *>(pD);
    A *pA = dynamic_cast<A *>(pB);
}

 3.const_cast

         主要用来去掉类型的const、volatile和__unligned属性。形式为:

const_cast<type>(expression);

        常量指针被转换成非常量指针,并且仍然指向原来的对象;常量引用被转换成非常量引用,并且仍然引用原来的对象。

const char *pc;
char *p = const_cast<char*>(pc);

4.reinterpret_cast

    非常激进的类型转换,形式为:

reinterpret<type>(expression);

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

    dynamic_cast是在运行时检查,其他3种都是在编译时完成。

猜你喜欢

转载自blog.csdn.net/qq_38196982/article/details/120295123