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

前言

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

cast-name<type>(expression)
其中type是转换的目标类型而expression是要转换的值。如果type是引用类型,则结果是左值。cast-name是static_cast、const_cast、reinterpret_cast和dynamic_cast四者之一。
考虑如下代码:

int a = 9;
int& b = static_cast<int&>(a); //转换结果为左值,可以引用
int& c = static_cast<int>(a); //转换结果为右值,将会报错

staic_cast

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

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

2.类继承层次间的上行或下行转换,基类允许不含有虚函数;
上行转换:将基类的指针或引用绑定到子类对象上,是一种安全的隐式转换规则;
下行转换:将子类的指针或引用绑定到基类对象上,是一种不安全的转换;如果基类本身指向子类,则该转换是安全的,否则为不安全。该种强制转换之所以不安全,是因为无法通过转换生成的变量来进行判断。

class A{
};
class B:public A{
}
int main(){
	A* a=new A;
	B* b=a;//将会报错
	B* b=static_cast<B*>(a); //下行转换,此时b也不为null,无法判断该转换是否合法。
	A *c=static_cast<A*>(b);//上行转换,等价于 A* c=b;
	return 0;
}

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

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

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

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

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

const_cast

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

int main()
{
    const char* pc = "abc";
    char* p = const_cast<char*>(pc);
    //p[0] = 'd'; //取消注释将会报: 写入访问权限冲突。
    //以下发现可对执行const_cast转换后的对象进行写操作
    const int a = 3;
    int& b = const_cast<int&>(a);
    //float& c = const_cast<float&>(b); //取消注释将报错,因为更改了数据类型
    b = 5;
    cout << "a = " << a << endl; //3
    cout << "b = " << b << endl;  //5
    printf("a的地址: %p\n",&a);
    printf("b的地址为: %p\n",&b);
    const int j = 3;
    int* ptr = const_cast<int*>(&j);
    *ptr = 5;
    cout << "j = " << j << endl;        //3 
    cout << "*ptr = " << *ptr << endl;     // 5
    printf("j的地址:  %p\n",&j);
    printf("ptr所指向的地址:  %p\n",ptr);
    return 0;
}

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

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

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

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

reinterpret_cast

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

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

dynamic_cast

dynamic_cast是个运行时的概念,在运行时会执行动态检查,主要用于安全的下行转换;
(1)其他三种都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查。
(2)不能用于内置的基本数据类型的强制转换。
(3)使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过。
(4)dynamic_cast转换如果成功的话返回的是指向类的指针或引用,如果失败的话,对于指针类型,返回null, 对于引用类型,则会报错。

(5)在类的转换时,在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。在进行下行转换时,dynamic_cast具有类型检查的功能,比 static_cast更安全。向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。

class A{
	public: virtual void f() { cout<<"hello"<<endl; };
};
class B:public A{
	public: void f() { cout<<"hello2"<<endl; };
};
class C{
	void pp() { return; }
};
int fun() {
	return 1;
}
int main() {
	A* a1=new B;//a1是A类型的指针指向一个B类型的对象
	A* a2=new A;//a2是A类型的指针指向一个A类型的对象
	B* b; C* c;
	b=dynamic_cast<B*>(a1);//结果为not null,向下转换成功,a1之前指向的就是B类型的对象。
	if(b==NULL) {
		cout<<"null"<<endl;
	} else {	
		cout<<"not null"<<endl;
	}
	b=dynamic_cast<B*>(a2);//结果为null,向下转换失败
	if(b==NULL) {
		cout<<"null"<<endl;
	} else {
		cout<<"not null"<<endl;
	}
	c=dynamic_cast<C*>(a2);//结果为null,向下转换失败
	if(c==NULL) {
		cout<<"null"<<endl;
	} else {
		cout<<"not null"<<endl;
	}
	return 0;
}

参考

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++中有四种强制类型转换,分别是reinterpret_cast、const_cast、static_cast和dynamic_cast。 reinterpret_cast用于进行底层的重新解释转换,可以将一个指针或引用转换为其他类型的指针或引用,甚至可以将指针转换为整数类型。但是使用reinterpret_cast需要非常小心,因为它是一种非常危险的操作,可能会导致未定义的行为。 const_cast用于移除const属性,可以将const修饰的变量或指针转换为非const类型。这可以用于去除const限定符,从而修改被const修饰的变量的值。 static_cast用于进行常见的类型转换,可以将一个表达式转换为另一种类型,例如基本数据类型之间的转换、父类指针或引用转换为子类指针或引用、以及void指针和任意类型的指针之间的转换。但是需要注意,在进行父类到子类的转换时,只有当父类指针或引用实际上指向了一个子类对象时,才能进行成功的转换。 dynamic_cast用于在继承关系中进行安全的向下转型(downcasting)。它可以将一个父类指针或引用转换为子类指针或引用,同时会进行类型检查,确保转换是安全的。如果转换失败,dynamic_cast会返回一个空指针或抛出一个std::bad_cast异常。 这四种强制类型转换在不同的场景下有不同的应用,可以根据具体的需求选择合适的转换方式。但是需要注意,在使用这些强制类型转换时,一定要谨慎和慎重,确保转换的安全性和正确性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C++中的类型转换static_cast、dynamic_cast、const_cast和reinterpret_cast总结](https://download.csdn.net/download/weixin_38629976/12808232)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [C++的四种类型转换reinterpret_cast/const_cast/static_cast /dynamic_cast](https://blog.csdn.net/salmonwilliam/article/details/113941785)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [C++四种cast转换(const_cast、static_cast、dynamic_cast、reinpreter_cast)类型转换运算符](https://blog.csdn.net/Dontla/article/details/130792118)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值