1. C语言与C++类型转换的区别
(1)C语言中的类型转换
1.转换太过随意,可以在任意类型之间转换。
2.C风格的转换没有统一的关键字和标示符。对于大型系统,做代码排查时容易遗漏和忽略。
(2)C++为了解决了上面两个问题。
1.对类型转换做了细分,提供了四种不同类型转换,以支持不同需求的转换;
2.类型转换有了统一的标示符,利于代码排查和检视。
下面分别来介绍这四种转换:static_cast、dynamic_cast、const_cast和reinterpre_cast.
1.1 static_cast强制类型转换
(1) 基本用法:static_cast<type-id> expression
(2) 用于基本类型间的转换,但是不能用于基本类型指针之间的转换
(3)用于类层次结构中基类和派生类之间指针或引用的转换
上行转换(派生类---->基类)是安全的;
下行转换(基类---->派生类)由于没有动态类型检查,所以是不安全的。
因为static_cast在编译期间转换的,无法在运行时检测类型,所以类型之间的转换可能存在风险
(4) 把任何类型的表达式转为void类型
(5) 使用特点
a、主要执行非多态的转换操作,用于代替C中通常的转换操作
b、隐式转换都建议使用static_cast进行标明和替换
#include <iostream>
using namespace std;
class Parent
{
};
class Child :public Parent
{
};
int main(void)
{
int a = 1;
char ch = 'x';
a = static_cast<int>(ch); //用于普通类型之间的转换
//int *p = static_cast<int *>(&ch);
Parent p;
Child c;
//p = c;
p = static_cast<Parent>(c); //用于有继承关系的类对象之间的转换
//c = static_cast<Child>(p);
Parent *p1 = static_cast<Parent *>(&c); //类对象指针之间的转换
}
1.2 reinterpret_cast
1.基本用法:reinterpret_cast<type-id> expression
2.使用场景:
(1) 用于普通指针和引用之间的转换 (任意转换,不安全)
(2) 用于数字和指针之间的转换 (很容易造成野指针)
3.使用特点:比较危险,一般不推荐使用
#include <iostream>
using namespace std;
int main(void)
{
int c = 200;
int b = 100;
char *p = reinterpret_cast<char *>(&c); //用于普通指针之间的转换(不安全)
cout << *(p + 1) << endl;
//cout << *(&b + 1) << endl;
int *q = reinterpret_cast<int *>(100); //用于数字和指针之间的转换(很容易出现野指针)
*q = 1;
return 0;
}
1.3 const_cast
1.基本用法:const_cast<type-id>expression 注:type-id只能是指针或者引用,或是指向对象类型成员的指针
2.使用场景:
(1) 常量指针转换为非常量指针,并且仍然指向原来的对象
(2) 常量引用被转换为非常量引用,并且仍然指向原来的对象
3.使用特点:
(1) cosnt_cast是四种类型转换符中唯一可以对常量进行操作的转换符
(2) 去除常量性是一个危险的动作,尽量避免使用。
c++中被const修饰的变量会被放在符号表里面,是一个真正的常量,如果对该常量取地址,则会在栈区重新
开辟一段新的空间,与之前符号标的常量无关
#include<iostream>
using namespace std;
int main(void)
{
const int a=1;//常量
int *p=const_cast<int*>(&a); //如果对该常量取地址,则会在栈区重新开辟一段新的空间,与之前符号标中的常量无关
*p=100;
cout<<a<<endl;
cout<<*p<<endl;
const int &m=1;
int &n=const_cast<int &>(m); //去const化
n=100;
cout<<"m="<<m<<endl;
cout<<"n= "<<n<<endl;
const int x=1;
int &y=const_cast<int&>(x); //非指针,引用类型,不改变原常量
y=222;
cout<<"x="<<x<<endl;
cout<<"y= "<<y<<endl;
int z=200;
const int*p1=&z;
int *q=const_cast<int*>(p1); //指针类型去const化
*q=999;
cout<<"*p1="<<*p1<<endl;
cout<<"*q="<<*q<<endl;
return 0;
}
//c++中被const修饰的变量会被放在符号表里面,是一个真正的常量,存放在常量区,如果对该常量取地址,则会在栈区重新
// 开辟一段新的空间,与之前符号标的常量无关
1.4 dynamic_cast
1.基本用法:dynamic_cast<type-id> expression
2.使用场景:只有在派生类之间转换时才使用dynamic_cast,type-id必须是类指针,类引用或者void*。
3.使用特点:
(1) 基类必须要有虚函数,因为dynamic_cast是运行时类型检查,需要运行时类型信息,而这个信息是存储在类的虚函数表 中,只有一个类定义了虚函数,才会有虚函数表(如果一个类没有虚函数,那么一般意义上,这个类的设计者也不想 它成 为一个基类)。
(2) 对于下行转换,dynamic_cast是安全的(当类型不一致时,转换过来的是空指针),而static_cast是不安全的(当类型不 一致时,转换过来的是错误意义的指针,可能造成踩内存,非法访问等各种问题)
(3) dynamic_cast还可以进行交叉转换
#include <iostream>
using namespace std;
class Parent
{
public:
virtual void f()
{
}
};
class Child :public Parent
{
public:
void f()
{
}
};
int main(void)
{
Child *c = new Child;
delete c;
//c = static_cast<Child *>(new Parent); //派生类指针指向基类对象(错误)
c = dynamic_cast<Child *>(new Parent); //运行时候会进行类型检查,不能转换,会返回NULL,比static_cast安全
if (NULL == c)
{
cout << "转换失败" << endl;
}
else
{
cout << "转换成功" << endl;
delete c;
}
return 0;
}
总结:
1. 去const属性用const_cast。
2. 基本类型转换用static_cast。
3. 多态类之间的类型转换用daynamic_cast。
4. 不同类型的指针类型转换用reinterpret_cast。