一、隐式转换
这样的转换也可以叫做隐式转换,类似 小的类型转为大的类型int i = 10; double j = i;
此时隐式将Int类型转换成了double类型。
二、显式转换
double j = 10.0;
int i = int(j);
三、static_cast关键字(编译时类型检查)
用法:static_cast<type_id>(expression),改运算符把expression转换为type_id类型,没有运行时类型检查。
它主要有如下几种用法:
(1)用于基本数据类型之间的转换,如把int转换为char,把int转换成enum,但这种转换的安全性需要开发者自己保证(这可以理解为保证数据的精度,即程序员能不能保证自己想要的程序安全),如在把int转换为char时,如果char没有足够的比特位来存放int的值(int>127或int<-127时),那么static_cast所做的只是简单的截断,及简单地把int的低8位复制到char的8位中,并直接抛弃高位。
(2)把空指针转换成目标类型的空指针
(3)把任何类型的表达式类型转换成void类型
(4)用于类层次结构中父类和子类之间指针和引用的转换
四、dynamic_cast关键字(运行时类型检查)
dynamic_cast主要用于类层次结构父类和子类之间的指针以及引用间的转换,由于有运行时类型检查,保证了下行转换的安全性(转换正确返回正确指针,返回错误则返回NULL)。
类层次的转换包含两种:
(1)上行转换:子类->父类
(2)下行转换:父类->子类
//上行转换
class A
{
virtual void fun(){};
}
calss B:public A
{
}
int main()
{
B * pB = new B;
A * pA = dynamic_cast<A *>(pB);//ok 子类 -> 父类
}
对于上行转换,static_cast和dynamic_cast效果一样,都安全;
//下行转换
class Base
{
virtual void fun(){};
}
calss Base:public Derived
{
}
int main()
{
Base* pB1 = new Dervied;//pB1指向派生类
Base* pB2 = new Base;//pB2指向基类
Dervied* pD1 = dynamic_cast<Dervied*>(pB1);//Ok
Dervied* pD2 = dynamic_cast<Dervied*>(pB2);//指向父类的指针转换 结果为NULL 此处转换不成功
}
对于下行转换:你必须确定要转换的数据确实是目标类型的数据,即需要注意:要转换的父类指针是否真的指向子类对象,如果是,static_cast和dynamic_cast都能成功;如果不是static_cast能返回,但是不安全,可能会出现访问越界错误,而dynamic_cast在运行时类型检查过程中,判定该过程不能转换,返回NULL。
//转换为"void *"
class A
{
public:
virtual void f(){}
};
class B
{
public:
virtual void f(){}
};
int main()
{
A *pA = new A;
B *pB = new B;
void *pV = dynamic_cast<void *>(pA);
pV = dynamic_cast<void *>(pB);
}
但是,在类A和类B中必须包含虚函数,为什么呢?因为类中存在虚函数,就说明它有想让基类指针或引用指向派生类对象的情况,此时转换才有意义;由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表。
//陷阱
class A
{
virtual void Func() = 0;
};
class B : public A
{
void Func(){};
};
class C : public A
{
void Func(){};
};
class D : public B, public C
{
void Func(){}
};
int main()
{
D *pD = new D;
A *pA = dynamic_cast<A *>(pD);
}
如果进行上面的直接转,你将会得到一个NULL的pA指针;这是因为,B和C都继承了A,并且都实现了虚函数Func,导致在进行转换时,无法进行抉择应该向哪个A进行转换。
正确的做法是:
int main()
{
D *pD = new D;
B *pB = dynamic_cast<B *>(pD);
A *pA = dynamic_cast<A *>(pB);
}
五、const_cast转换格式:const_cast (expression)
const_cast用来将类型的const、volatile和__unaligned属性移除。常量指针被转换成非常量指针,并且仍然指向原来的对象;常量引用被转换成非常量引用,并且仍然引用原来的对象。
#include <iostream>
using namespace std;
class CA
{
public:
CA():m_iA(10){}
int m_iA;
};
int main()
{
const CA *pA = new CA;
// pA->m_iA = 100; // Error
CA *pB = const_cast<CA *>(pA);
pB->m_iA = 100;
// Now the pA and the pB points to the same object
cout<<pA->m_iA<<endl;
cout<<pB->m_iA<<endl;
const CA &a = *pA;
// a.m_iA = 200; // Error
CA &b = const_cast<CA &>(a);
b.m_iA = 200;
// Now the a and the b reference to the same object
cout<<b.m_iA<<endl;
cout<<a.m_iA<<endl;
}
注:你不能直接对非指针和非引用的变量使用const_cast操作符去直接移除它的const、volatile和__unaligned属性。
六、reinterpret_cast的转换格式:reinterpret_cast (expression)
允许将任何指针类型转换为其它的指针类型;听起来很强大,但是也很不靠谱。
它主要用于将一种数据类型从一种类型转换为另一种类型。
它可以将一个指针转换成一个整数,也可以将一个整数转换成一个指针,在实际开发中,先把一个指针转换成一个整数,在把该整数转换成原类型的指针,还可以得到原来的指针值;
特别是开辟了系统全局的内存空间,需要在多个应用程序之间使用时,需要彼此共享,传递这个内存空间的指针时,就可以将指针转换成整数值,得到以后,再将整数值转换成指针,进行对应的操作。