【C++】强制类型转换

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wei_cheng18/article/details/81262346

C++中四种强制类型转换:static_cast, reinterpret_cast, const_cast, dynamic_cast

1. static_cast(编译时类型检查)

用于非多态类型之间的转换(静态转换),任何标准类型之间都可以用它,但它不能用于不相关类型之间的转换。主要有以下几种用法:

  1. 用于基本的数据类型之间的转换,例如把int转换为char,把int转换为enum,但这种转换的安全性需要开发者自己保证,static_cast所做的只是简单的截断;
  2. 空指针转换成目标类型的空指针;
  3. 任何类型的表达式转换成void类型;
  4. 用于层次结构中父类和子类之间指针和引用的转换;

对于第4点,存在两种形式的转换,上行转换(子类到父类),下行转换(父类到子类);对于static_cast,从子类到父类的转换是安全的,因为子类包含了父类的所有数据成员和函数成员,从子类转换到父类的指针对象可以没有任何顾虑的访问其成员;而对于从父类到子类的转换,因为static_cast是在编译时进行类型检测,没有运行时的类型检查,是不安全的。

void Test() 
{
    double i = 2;
    int d = static_cast<int>(i);
    printf("%lf, %d\n", i, d);
}
2. dynamic_cast(运行时类型检查)

主要用于类层次结构中父类和子类之间指针和引用的转换,由于具有运行时类型检查,可以保证下行转换(父类到子类)的安全性,即:转换成功就返回转换后的正确类型指针,如果失败,返回NULL;而static_cast如果失败,不会返回NULL,所以不安全。

总结为以下两句:

  • 对于上行转换,从子类到父类的转换,子类的指针指向的是子类对象,一般不会指向父类对象,所以static_cast和dynamic_cast效果一样;
  • 对于下行转换,从父类到子类的转换,如果父类的指针指向的是父类对象,那么static_cast就会不安全,而dynamic_cast在运行时检查过程中,判定不能转换,返回NULL;如果父类的指针指向子类对象,那么两个也都能成功。
class Base
{
    virtual void fun()
    {}
};
class Derived :public Base
{
};

void Test()
{
    Derived* pb = new Derived; // 子类转父类
    Base* pb1 = static_cast<Base*>(pb);
    Base* pb2 = dynamic_cast<Base*>(pb);

    Base *p1 = new Derived; // 父类转子类,父类指针指向子类对象
    Derived *pd1 = static_cast<Derived *>(p1);
    Derived *pd2 = dynamic_cast<Derived *>(p1);

    Base *p2 = new Base; // 父类转子类,父类指针指向父类对象
    Derived *pd3 = static_cast<Derived *>(p2); // 不安全
    Derived *pd4 = dynamic_cast<Derived *>(p2); //pd4 = NULL;
}
3. reinterpret_cast

用于将一种类型转换为另一种不同的类型。用于底层的强制类型转换,导致实现依赖的结果(不可移植),例如:将一个指针转换为整数。

typedef void(*FUNC)();
int DoSomething(int i) 
{
    cout << "DoSomething" << endl;
    return 0;
}
void Test() 
{
    FUNC f = reinterpret_cast<FUNC>(DoSomething);
    f();

    int i = 0;
    int p = reinterpret_cast<int>(&i);//将指针转换为整数
}
4. reinterpret_cast

删除变量的const属性,方便赋值。

void test()
{
    const int a = 5;
    int* pa = const_cast<int *>(&a);
    *pa = 10;
    cout << a << endl; //打印的结果还是5,由内存窗口可以看到值已经被改,因为编译器优化,到寄存器中取值
    cout << *pa << endl; //结果是10,pa指向内存中的a,改的是内存中的值
}
void test()
{
    volatile const int a = 5;
    int* pa = const_cast<int *>(&a);
    *pa = 10;
    cout << a << endl; //打印的结是10,被volatile修饰,从内存中读取数据,解锁是10
    cout << *pa << endl; 
}

猜你喜欢

转载自blog.csdn.net/wei_cheng18/article/details/81262346