c++中四种cast转化
1.const_cast转化
const变量👉非const变量
•常量指针转化为非常量的指针,并且仍然指向原来的对象
•常量引用转化为非常量的引用,并且仍然指向原来的对象
(★const_cast只能改变运算对象的底层const,而对顶层const无能为力
★const_cast不能改变表达式类型,只能改变常量属性)
1.去掉const常量const属性
const int g = 20;
int h = const_cast<int>(&g);
2.去掉const引用const属性
const int g = 20; int &h = const_cast<int &>(g);
3.去掉const指针const属性
const char *g = “hello”; char *h = c
onst_cast<char *>(g);
使用:
1.一个函数的参数不是const对象,并且编程者事先已经知道在这个函数中不会对参 数进行修改,但需要传递的实参却是已经定义好的const对象。为了成功调用这个函数,就需要利用到const_cast在实参传递前对其进行处理,从而使函数能够成功接收这个实参
#include<iostream>
using namespace std;
void Function(int *val){
cout<<*val<<endl;
}
int main(){
const int value=21;
Function(const_cast<int*>(&value));
return 0;
}
2.如果我们定义了一个非const的变量,却使用了一个指向const对象的指针来指向它, 而在程序的某处希望改变这个变量时发现只有指针可用,此时就可const_cast进行处理
#include<iostream>
using namespace std;
int main(){
int value=26;
const int* const_ptr=&value;
int* ptr=const_cast<int*>(const_ptr);
*ptr=3;
cout<<"value:"<<value<<endl;
cout<<"*const_ptr:"<<*const_ptr<<endl;
cout<<"ptr:" <<*ptr<<endl;
return 0;
}
输出:
2.static_cast转化
1.各种隐式转化
非const👉const,void*👉指针
2.能用于多态向上转化,向下转换可成功但不安全
用法
①用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。
进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
③把空指针转换成目标类型的空指针。
④把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expression的const、volatile、或者__unaligned属性。
基本数据类型
char a = 'a';
int b = static_cast<char>(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属性
类上行和类下行转化
if(Derived *dp = static_cast<Derived *>(bp)){//下行转换是不安全的
//使用dp指向的Derived对象
}
else{
//使用bp指向的Base对象
}
if(Base*bp = static_cast<Derived *>(dp)){//上行转换是安全的
//使用bp指向的Derived对象
}
else{
//使用dp指向的Base对象
}
3.dynamic_cast转化
用于动态类型转化,只能用于含有虚函数的类,用于类层次之间的向上和向下转化。
⭐只能转指针或引用。
如果一条dynamic_cast语句的转换目标是指针类型并且失败了,则结果为0。如果转换目标是引用类型并且失败了,则dynamic_cast运算符将抛出一个std::bad_cast异常(该异常定义在typeinfo标准库头文件中)。
(1)指针类型:
举例,Base为包含至少一个虚函数的基类,Derived是Base的共有派生类,如果有一个指向Base的指针bp,我们可以在运行时将它转换成指向Derived的指针,代码如下:
if(Derived *dp = dynamic_cast<Derived *>(bp)){
//使用dp指向的Derived对象
}
else{
//使用bp指向的Base对象
}
(2)引用类型:
因为不存在所谓空引用,所以引用类型的dynamic_cast转换与指针类型不同,在引用转换失败时,会抛出std::bad_cast异常,该异常定义在头文件typeinfo中。
void f(const Base &b){
try{
const Derived &d = dynamic_cast<const Base &>(b);
//使用b引用的Derived对象
}
catch(std::bad_cast){
//处理类型转换失败的情况
}
}
4.reinterpret_cast转化
几乎什么都可以转
⭐new_type必须是一个指针、引用、算术类型、函数指针或者成员指针。
举一个错误使用reintepret_cast例子,将整数类型转换成函数指针后,vc++在执行过程中会报"…中的 0xxxxxxxxx 处有未经处理的异常: 0xC0000005: Access violation"错误:
#include <iostream>
using namespace std;
int output(int p){
cout << p <<endl;
return 0;
}
typedef int (*test_func)(int );//定义函数指针test_func
int main(){
int p = 10;
test_func fun1 = output;
fun1(p);//正确
test_func fun2 = reinterpret_cast<test_func>(&p);
fun2(p);//...处有未经处理的异常: 0xC0000005: Access violation
return 0;
}`
错误的使用reinterpret_cast很容易导致程序的不安全,只有将转换后的类型值转换回到其原始类型,这样才是正确使用reinterpret_cast方式。
MSDN中也提到了,实际中可将reinterpret_cast应用到哈希函数中,如下(64位系统中需将unsigned int修改为unsigned long):
// expre_reinterpret_cast_Operator.cpp
// compile with: /EHsc
#include <iostream>
// Returns a hash code based on an address
unsigned short Hash( void *p ) {
unsigned int val = reinterpret_cast<unsigned int>( p );
return ( unsigned short )( val ^ (val >> 16));
}
using namespace std;
int main() {
int a[20];
for ( int i = 0; i < 20; i++ )
cout << Hash( a + i ) << endl;
}
5.为什么不使用强制转化?
c的强制转化表面上看起来功能强大,什么都可以转,但是转化不明确,不能进行错误检查,容易出错。
参考:“SpartacusIn21”博客