首页 > 技术文章 > C++类型转换运算符

jakelin 2021-01-25 14:26 原文

  • dynamic_cast:有虚函数的类,指针或引用,类层次结构中进行转换(主要是向上转换);
  • const_cast:去掉 const 或 volatile 属性;
  • static_cast:编译期间转换,没有运行时类型检查来保证转换的安全性;
  • reinterpret_cast:仅仅重新解释类型,没有对数据进行调整。

dynamic_cast

static_cast < new_type > ( expression )

dynamic_cast动态类型转换,用于实现RTTI。只能用于含有虚函数的类,用于类层次间的向上和向下转化。只能转指针或引用。向下转化时,如果是非法的对于指针返回NULL,对于引用抛异常bad_cast

  • 只能用于有虚函数的类;

  • 只能用于指针引用

  • 对运行期类型信息(RTTI)进行了检查,类层次结构中向上转换成功,其余转换返回空指针;

    若是基类指针指向派生类对象,再将基类指针向下转型,成功!

#include <iostream>
using namespace std;

class A{
public:
    virtual void func() const { cout<<"Class A"<<endl; }
};

class B: public A{
public:
    virtual void func() const { cout<<"Class B"<<endl; }
};

class C: public B{
public:
    virtual void func() const { cout<<"Class C"<<endl; }
};

class D: public C{
public:
    virtual void func() const { cout<<"Class D"<<endl; }
};

int main(){
    A *pa = new A();
   
    //情况①
    B *pb = dynamic_cast<B*>(pa);  //向下转型失败 赋值NULL
    C *pc = dynamic_cast<C*>(pa);  //向下转型失败 赋值NULL
   
    //情况②
    pa = new D();  //向上转型都是允许的
    pb = dynamic_cast<B*>(pa);  //向下转型成功
    pc = dynamic_cast<C*>(pa);  //向下转型成功
   
    return 0;
}

const_cast

const_cast < new_type > ( expression )		

修改类型的 constvolatile 属性。除了 const 或 volatile 修饰之外, new_type 和 expression 的类型必须是一样的。

函数指针和成员函数指针不可用于 const_cast

expression 内存空间是只读的,转换类型后,只能读,不能写转换后的指针或引用能修改值,源数据值却未改变,但是他们的地址是同一个!!!

#include<iostream>
int main() {
    int i = 3;                 // 不声明 i 为 const
    const int& rci = i; 
    const_cast<int&>(rci) = 4; // OK:修改 i
    std::cout << "i = " << i << std::endl; // i = 4
    
    const int c_val = 233;  //声明为常量类型
    int &use_val = const_cast<int&>(c_val); //使用去const 引用
    int *ptr_val = const_cast<int*>(&c_val);//使用去const 指针
    std::cout << "&c_val = " << &c_val << std::endl;
    
    use_val = 111;  //未定义行为
    std::cout << c_val << "\t" << use_val << "\t" << *ptr_val << "\t&use_val = " << &use_val << std::endl;
    
    *ptr_val = 222; //未定义行为
    std::cout << c_val << "\t" << use_val << "\t" << *ptr_val << "\tptr_val = " << ptr_val << std::endl;
    // std::cout << "&c_val = " << &c_val << std::endl;
    return 0;
}
/*  https://zh.cppreference.com/w/cpp/language/const_cast  输出为
	i = 4
    &c_val = 0x7ffd3abc86cc
    233	111	111	&use_val = 0x7ffd3abc86cc
    233	222	222	ptr_val = 0x7ffd3abc86cc
*/

static_cast

static_cast < new_type > ( expression )

static_cast 作用和C语言风格强制转换的效果基本一样,由于没有运行时类型检查来保证转换的安全性,所以这类型的强制转换和C语言风格的强制转换都有安全隐患。static_cast 是“静态转换”的意思,也就是在编译期间转换,转换失败的话会抛出一个编译错误。

  • 能使用隐式转换的地方,均可以使用static_cast转换;
  • 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证;
  • 如果类型不兼容,使用static_cast编译检查,会报错;
  • 类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。向上转换是安全的,向下转换不安全;
  • 把void指针转换成目标类型的指针(不安全!!);
  • 把任何类型的表达式转换成void类型。
//下面是正确的用法
int m = 100;
long n = static_cast<long>(m);  //宽转换,没有信息丢失
char ch = static_cast<char>(m);  //窄转换,可能会丢失信息
int *p1 = static_cast<int*>( malloc(10 * sizeof(int)) );  //将void指针转换为具体类型指针
void *p2 = static_cast<void*>(p1);  //将具体类型指针,转换为void指针
//下面的用法是错误的
float *p3 = static_cast<float*>(p1);  //不能在两个具体类型的指针之间进行转换
p3 = static_cast<float*>(0X2DF9);  //不能将整数转换为指针类型	

//  上行 Sub -> Base
//编译通过,安全
Sub sub;
Base *base_ptr = static_cast<Base*>(&sub);  

//  下行 Base -> Sub
//编译通过,不安全
Base base;
Sub *sub_ptr = static_cast<Sub*>(&base);  

reinterpret_cast

reinterpret_cast< new_type > ( expression )

用于高度危险的类型转换,仅仅是对二进制位的重新解释,不会对数据进行调整。

char *p1  = "hello world";                       
int  *p2  = reinterpret_cast<int *>(p1);

推荐阅读