强制类型转换运算符
1. const_cast
用于删除 const、volatile 和 __unaligned 特性(如将 const int 类型转换为 int 类型 )
#include <iostream>
using namespace std;
class CCTest {
private:
int m_number;
public:
void Number(int num) {
m_number = num;
}
void printNumber() const {
cout << " Transform Before:" << m_number<<endl;
const_cast<CCTest*>(this)->m_number--;
cout << " Transform Later:" << m_number<<endl;
}
};
int main() {
CCTest test;
test.Number(8);
test.printNumber();
return 0;
}
2. static_cast
用于非多态类型的转换
不执行运行时类型检查(转换安全性不如 dynamic_cast)
通常用于转换数值数据类型(如 float -> int)
可以在整个类层次结构中移动指针,子类转化为父类安全(向上转换),父类转化为子类不安全(因为子类可能有不在父类的字段或方法)
向上转换是一种隐式转换。
typedef unsigned char BYTE
void main() {
char mychar;
int i=65;
float f=2.5;
double db;
ch=static_cast<char>(i);
db=static_cast<double>(f);
i=static_cast<BYTE>(ch);
}
3. dynamic_cast
用于多态类型的转换 要使用dynamic_cast类中必须定义虚函数
执行行运行时类型检查
只适用于指针或引用
对不明确的指针的转换将失败(返回 nullptr),但不引发异常,对于引用抛异常。
可以在整个类层次结构中移动指针,包括向上转换、向下转换
向上转换: 指的是子类向基类的转换。
向下转换: 指的是基类向子类的转换。
class Base{
public:
virtual void fun(){}
};
class Drived : public base{
public:
int i;
};
Base *Bptr = new Drived();//#1
Derived *Dptr1 = static_cast<Derived *>(Bptr); //#2
Derived *Dptr2 = dynamic_cast<Derived *>(Bptr); //#3
此时#1和#2都是安全的,因为此时Bptr确实是指向的派生类,虽然其类型被声明为Base*,但是其实际指向的内容其实是Drived对象,所以#1和#2都是安全的,Dptr1和Dptr2可以正常接受转换。
若把#1修改为
Base *Bptr = new Base();
这样#1就不安全了,static_cast不支持类型检查,向下转换,因为子类可能有不在父类的字段或方法,可能导致错误。例如访问子类的成员可能得到一个垃圾任意值。
但dynamic_cast由于类型检查,返回一个空指针,对空指针进行操作,将报错提前知晓错误所在。这也就是dynatic_cast比static_cast安全的原因。
class Base1{
virtual void f1(){}
};
class Base2{
virtual void f2(){}
};
class Derived: public Base1, public Base2{
void f1(){}
void f2(){}
};
Base1 *pD = new Derived;
Derived *pD1 = dynamic_cast<Derived*>(pD); //ok
Derived *pD2 = static_cast<Derived*>(pD); //ok
Base2 *pB1 = dynamic_cast<Base2*>(pD); //#1
Base2 *pB2 = static_cast<Base2*>(pD); //#2
此时的#1,将pD的类型转化为Base2*,即:使得pB1指向Drived对象的Base2子对象,为什么能达到这种转化?因为dynamic_cast是运行时才决定真正的类型,在运行时发现虽然此时pD的类型是Base1*,但是实际指向的是Derived类型的对象,那么就可以通过调整指针,来达到pB1指向Derived 对象的Base2子对象的目的;
但是#2就不行了,其使用的是static_cast,它不涉及运行时的类型检查,对于它来讲,pD的类型是Base1*,Base1和Base2没有任何关系,那就会出现编译错误了。error: invalid static_cast from type ‘Base1*’ to type ‘Base2*’
tips:对于多种继承,如果pD真的是指向Derived,使用static_cast和dynamic_cast都可以转化为Derived,但是如果要转化为Base1的兄弟类Base2,必须使用dynamic_cast,使用static_cast不能通过编译。
因为Derived和Base1和Base2*之间存在隐式转化,可以将语句2修改为:
Base2 *pB2 = static_cast<Base2*>(static_cast<Derived*>(pD));//Base1的指针先转为Derived类指针,再转为Base2指针
参考文献:https://blog.csdn.net/baidu_35679960/article/details/80821222
4. reinterpret_cast
用于位的简单重新解释
滥用 reinterpret_cast 运算符可能很容易带来风险。 除非所需转换本身是低级别的,否则应使用其他强制转换运算符之一。
允许将任何指针转换为任何其他指针类型(如 char* 到 int* 或 One_class* 到 Unrelated_class* 之类的转换,但其本身并不安全)
也允许将任何整数类型转换为任何指针类型以及反向转换。
reinterpret_cast 运算符不能丢掉 const、volatile 或 __unaligned 特性。
reinterpret_cast 的一个实际用途是在哈希函数中,即,通过让两个不同的值几乎不以相同的索引结尾的方式将值映射到索引。
#include <iostream>
using namespace std;
//一个实际用途是在哈希函数中
unsigned short Hashtable( void *p ) {
unsigned int val = reinterpret_cast<unsigned int>( p );
return ( unsigned short )( value ^ (vlue >> 16));
}
using namespace std;
int main() {
int a[20];
for ( int i = 0; i < 20; i++ )
cout << Hashtable( a + i ) << endl;
}