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

c++的四种强制转换类型

  • 前言
  • staic_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • 参考

前言

在c++中,显示强制转换类型具有如下形式:

cast-name(expression)
其中type是转换的目标类型而expression是要转换的值。如果type是引用类型,则结果是左值。cast-name是static_cast、dynamic_cast、const_cast和reinterpret_cast

staic_cast

用于具有明确定义的类型转换,不能用于底层const对象的转换以及两个不相关的类型进行转换(比如int型和int *型之间就不相关).
1.用于内置类型之间的转换,如果整数和浮点数之间,当显示的将较大的算术类型赋值给较小的类型是,编译器不会警告;默认情况下,会给出警告信息;

int main(){
	int a=11,b=3;
	double c=static_cast(a)/b;
    int d=c;// 编译器将给出警告信息
    int e=static_cast(c);// 无警告信息
    int *f=staic_cast(a);//将会报错
	return 0;
}

2.类继承层次间的上行或下行转换,基类允许不含有虚函数;
上行转换:将基类的指针或引用绑定到子类对象上,是一种安全的隐式转换规则;
下行转换:将子类的指针或引用绑定到基类对象上,是一种不安全的转换;

class A{
};
class B:public A{
}
int main(){
	A* a=new A;
	B* b=a;//将会报错
	B* b=static_cast(a); //下行转换,但是不安全
	A *c=static_cast(b);//上行转换,等价于 A* c=b;
	return 0;
}

3 对于编译器无法自动执行的类型转换也非常有用。例如,可以使用static_cast找回存在于void*指针中的值;

double a=10;
void *p=&a; //任何非常量对象的地址都能存入void *
double *dp=static_cast(p);

但是得注意,当把指针存放在void*中,并且使用static_cast将其强制转换回原来的类型时,应该确保指针的值保持不变。也就是说,强制转换的结果将与原始的地址值相等,因此,必须确保转换后所得到的类型就是指针所指的类型。类型一旦不符,将产生未定义的后果,考虑下面一个例子:

int a=9;
void *p=&a;
double * dp=static_cast(p);
cout<<*dp;  
int * da=staitc_cast(p);
cout<<*da;

输出如下:
在这里插入图片描述

dynamic_cast

dynamic_cast是个运行时的概念,在运行时会执行动态检查,主要用于安全的下行转换;
(1)其他三种都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查。
(2)不能用于内置的基本数据类型的强制转换。
(3)dynamic_cast转换如果成功的话返回的是指向类的指针或引用,如果失败的话,对于指针类型,返回null,对于引用类型,则会报错。
(4)使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过。
(5)在类的转换时,在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。在进行下行转换时,dynamic_cast具有类型检查的功能,比 static_cast更安全。向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。

class A{
public: virtual void f() { cout<<"hello"<(a1);//结果为not null,向下转换成功,a1之前指向的就是B类型的对象,所以可以转换成B类型的指针。
if(b==NULL)
{
cout<<"null"<(a2);//结果为null,向下转换失败
if(b==NULL)
{
cout<<"null"<(a2);//结果为null,向下转换失败
if(c==NULL)
{
cout<<"null"<

const_cast

唯一一个可以改变运算对象的底层const的强制转换,且被转换的对象要么是指针,要么是引用;const_cast只能改变对象的常量属性,不能改变对象的类型;C++ primer145页中,对const_cast的描述:如果对象本身不是一个常量,使用强制类型转换获得写权限是合法的行为。然而,如果对象是一个常量,再使用const_cast执行写操作就会产生未定义的后果。在visual studio2019上,尝试了下,发现,并不完全如此:

int main()
{
    const char* pc = "abc";
    char* p = const_cast(pc);
    p[0] = 'd'; //报错,引发了异常: 写入访问权限冲突。
    //以下发现可对执行const_cast转换后的对象进行写操作
   const int a = 3;
    int& b = const_cast(a);
    b = 5;
    cout << "a = " << a << endl; //3
    cout << "b = " << b << endl;  //5
    
    cout << "a的地址: " << &a << endl;
    cout << "b的地址: " << &b << endl;
    const int j = 3;
    int* p = const_cast(&j);
    *p = 5;
    cout << "j = " << j << endl;        //3 
    cout << "*p= " << *p << endl;     // 5
    cout << "j的地址: " << &j << endl;
    cout << "p所指向的地址: " << p << endl;
    return 0;
}

调试窗口:
C++四中强制类型转换static_cast、dynamic_cast、const_cast、reinterpret_cast_第1张图片
通过调试,发现a和b在内存中的值相同,j和*p在内存的值也相同;
最终的输出:
C++四中强制类型转换static_cast、dynamic_cast、const_cast、reinterpret_cast_第2张图片
通过输出,可以发现a和b的地址是一样的,p所指向的地址确为j的地址,但为什么值确不以样;
解释
C++编译器具有优化功能,当你定一个const的常量的时候,系统觉得它不会被改变了,于是做一个优化把该常量存到寄存器当中,下次访问的过程更快速一点. 所以当显示窗口读取数据的时候,他会直接去寄存器当中读取数据.而不是去内存,所以导致我们明明该掉了a的值,却打印不出来,但是如何解决这个问题呢??
c++有一个关键字: volatile 该关键字的作用防止编译器优化,此时,当打印常量时,会去内存中取值:

int main()
{
 
    volatile const int a = 3;
    int& b = const_cast(a);
    b = 5;
    cout << "a = " << a << endl; //5
    cout << "b = " << b << endl;  //5
    
    cout << "a的地址: " << &a << endl;
    cout << "b的地址: " << &b << endl;
    volatile const int j = 3;
    int* p = const_cast(&j);
    *p = 5;
    cout << "j = " << j << endl;        //5 
    cout << "*p= " << *p << endl;     // 5
    cout << "j的地址: " << &j << endl;
    cout << "p所指向的地址: " << p << endl;
    return 0;
}

reinterpret_cast

有着和C风格的强制转换同样的能力。它可以转化任何内置的数据类型为其他任何的数据类型,也可以转化任何指针类型为其他的类型。它甚至可以转化内置的数据类型为指针,无须考虑类型安全或者常量的情形。不到万不得已绝对不用。
它通常为运算对象的位模式提供较低层次上的重新解释,举个例子,假设有如下转换:

int *ip;
char *pc=reinterpret_cast(ip);
string str(pc); //pc实际上指向的是一个int型,虽然不会报错,但可能引发程序的异常行为

参考

《c++ primer》第五版
https://www.jb51.net/article/123307.htm
https://www.csdn.net/gather_29/NtTaYgysMTgtYmxvZwO0O0OO0O0O.html

你可能感兴趣的:(C++四中强制类型转换static_cast、dynamic_cast、const_cast、reinterpret_cast)