类型转换
隐式转换
要求:相互转换的类型兼容
当一个值被赋值到另一个兼容类型时,会自动发生隐式转换
但这样会造成精度损失
类对象之间也可以发生隐式转换
1
2
SubClass* pSub = new SubClass();
BaseClass* pBase = pSub;如上是将子类指针转换为了基类指针,这是常用的类指针间的隐式转换
若上方SubClass与BaseClass之间没有继承关系,他们的指针是无法进行隐式转换的
除非重载运算符或构造函数
1
2
3
4
class classA{};
class classB{
public: ClassB (const ClassA& a){}
};这种方法类似于拷贝构造,但参数类型不同,我们称这种为转换构造函数
显式转换
使用变量类型运算符
1
2
int a = 2;
float b = (float)a // 或float(a)以上将整型a转化为了浮点数
1
2
SubClass obj;
BaseClass* pBase = (BaseClass*) &obj;以上将子类对象obj的地址转换成了基类的指针,但若两者没有继承关系,则转换时可能会访问到奇怪的位置
动态转换
语法:dynamic_cast <转换类型> (表达式)
只能用于对象的指针和引用的转换
用于多态类的向下转换(向上转换一定可以成功,故可以直接使用普通类型转换)
dynamic_cast进行两个阶段的检查:
- 编译阶段:检查基类是否是多态类,不是会报错
- 运行阶段:检查转换对象是派生类对象,不是会返回空指针
动态转换需要RTTI
1
2
3
4
5
6
7
class CBase{
};
class CDerive: public CBase{};
CBase obj;
// 基类不是多态类,无法转换
CDerive *ptr = dynamic_cast<CDerived*>(&obj);1
2
3
4
5
6
7
8
9
class CBase{
public:
virtual ~CBase(){}
};
class CDerive: public CBase{};
CBase obj;
// 不是派生类对象,转换失败
CDerive *ptr = dynamic_cast<CDerived*>(&obj);静态转换
语法:static_cast <转换类型> (表达式)
可用于基类到派生类的向下转换与派生类到基类的向上转换
static_cast只进行编译阶段的检查:检查两个类是否兼容(不要求基类是多态类)
静态转换可以替代隐式转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class CBase{};
class CDerive: public CBase{};
class COther{};
CBase *p;
CDerive *p1;
COther other;
CDerive obj;
//
p = static_cast<CBase*>(&obj);
p1 = static_cast<CDerive*>(&obj);
// 会提示类型转换无效
p = static_cast<CBase*>(&other);
p1 = static_cast<CDerive*>(&other);重解释转换
语法:reinterpret_cast <转换类型> (表达式)
用于类指针之间的转换,而不会检查类型是否有效
也可用于整型与指针间的转换(注意整型的数据范围能容纳指针数值)
应用:
- 与内存和硬件直接交互的底层与接口程序
- 与操作系统组件交互
- 处理网络或多媒体数据
1
2
3
4
5
6
7
8
9
10
class CBase{};
class CDerive: public CBase{};
class COther{};
CBase *p;
CDerive *p1;
COther other;
p1 = reinterpret_cast<CDerive*>(0xEFL);
long long address = reinterpret_cast<long long>(&other);常量转换
语法:const_cast <转换类型> (表达式)
用于常量与非常量之间的转换,转换类型必须是指针或引用
应用:
- 在调用不修改对象但未声明常量参数的函数时,暂时取消对象的常量类型
- 临时取消对象中的const属性,以便调用成员函数修改其中成员
1
2
3
4
5
int hello(char* str){
cout <<str<<endl;
}
const char* str = "world!";
hello(const_cast<char*>(str));注意,进行转换不意味着可以进行修改