1、概述
传统运转换延续了C的形式,但是只能在数值类型上使用,对于其他类型(引用和指针),标准c++的有以下四种强制类型转换方式:
const_cast,reinterpret_cast,static_cast,dynamic_cast
2、const_cast
用法: const_cast <new_type> (expression)
const_cast
转换符是用来移除或添加变量的const
, volatile
, 和 __unaligned
限定符,而不能用于类型转换。
2.1 移除const
移除const操作。
const int constant = 12;
const int* p = &constant;
int* modifier = const_cast<int*>(p);
*modifier = 123;
cout<<*modifier<<endl;
2.2 添加const
int data = 13;
int *pdata = &data;
const int *result = const_cast<const int*>(pdata);
其他限定符,如volatile等与上面的类似。
3 static_cast
用法:static_cast <new_type> (expression)
该运算符把expression
转换为new_type
类型,但没有运行时类型检查来保证转换的安全性。
使用场景:
1 用于类层次结构中基类和子类之间指针或引用的转换。
进行上行转换(把子类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。
2 用于基本数据类型之间的转换
如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
3 把空指针转换成目标类型的空指针。
4 把任何类型的表达式转换成void类型。
使用实例:
class Data
{
public:
int data = 10;
virtual void get();
};
class SubData: public Data
{
};
SubData *sd = new SubData;
Data *d = static_cast<Data*>(sd);
SubData *sd2 = static_cast<SubData*>(d);
注意:
static_cast不能去掉expression的const、volitale、或者__unaligned属性
4 dynamic_cast
用法:dynamic_cast <new_type> (expression)
该运算符把expression
转换成new_type
类型的对象。参数说明:
new_type必须是类的指针、类的引用或者void *;
如果new_type是类指针类型,那么expression也必须是一个指针;
如果new_type是一个引用,那么expression也必须是一个引用。
使用场景:
1 只能在继承类对象的指针之间或引用之间进行类型转换
上行转换,同static_cast;
下行转换,dynamic_cast具有类型检查的功能,比static_cast更安全。
2 这种转换并非在编译时,而是在运行时,动态的
3 没有继承关系,但被转换的类具有虚函数对象的指针进行转换
注:只有对象具有多态属性的时候,才可以对齐进行dynamic_cast。
使用示例:
class NoExtend
{
virtual void set();
};
class NoExtend2
{
};
SubData *sd = new SubData;
Data *d = dynamic_cast<Data*>(sd);
Data &d2 = *d;
SubData &sd2 = dynamic_cast<SubData&>(d2);
NoExtend *ne = new NoExtend;
Data *d3 = dynamic_cast<Data*>(ne);
NoExtend2 *sd3 = dynamic_cast<NoExtend2*>(ne);
5、reinterpret_cast
用法: reinterpret_cast <new_type> (expression)
reinterpret_cast运算符是用来处理无关类型之间的转换;它会产生一个新的值,这个值会有与原始参数(expressoin)有完全相同的比特位。也即将一个类型指针转换为另一个类型指针,这种在转换不修改指针变量值数据存放格式。reinterpret_cast不能用于非指针的转换
使用场景:
reinterpret_cast用在任意指针(或引用)类型之间的转换,一般情况有以下这些常用场景:
从指针类型到一个足够大的整数类型
从整数类型或者枚举类型到指针类型
从一个指向函数的指针到另一个不同类型的指向函数的指针
从一个指向对象的指针到另一个不同类型的指向对象的指针
从一个指向类函数成员的指针到另一个指向不同类型的函数成员的指针
从一个指向类数据成员的指针到另一个指向不同类型的数据成员的指针
使用示例:
double d=12.34;
double* p = &d;
long* pi = reinterpret_cast<long *> (p);
class C1{};
class C2{};
C1* pc1 = new C1;
C2* pc2=reinterpret_cast<C2*>(pc1);
double* doub=reinterpret_cast<double*> (pc2);
6、interface_cast
interface_cast是android中定义的类型转换,其源码位于frameworks/native/include/binder/Iinterface.h
以下针对IServiceManager分析
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
其中INTERFACE为传入进来的IServiceManager,在IServiceManager中关于asInterface的实现部分,只有这一段IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
,它实际调用的还是Iinterface中的宏定义。
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
const android::String16 I##INTERFACE::descriptor(NAME); \
const android::String16& \
I##INTERFACE::getInterfaceDescriptor() const { \
return I##INTERFACE::descriptor; \
} \
android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
const android::sp<android::IBinder>& obj) \
{ \
android::sp<I##INTERFACE> intr; \
if (obj != NULL) { \
//根据name描述符,也就是"android.os.IServiceManager"通过方法 \
//queryLocalInterface查询本地是否有此Interface \
//没有就创建一个新的,其实是new BpServiceManager。 \
intr = static_cast<I##INTERFACE*>( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == NULL) { \
intr = new Bp##INTERFACE(obj); \
} \
} \
return intr; \
} \
I##INTERFACE::I##INTERFACE() { } \
I##INTERFACE::~I##INTERFACE() { } \
BpServiceManager的实现也位于ISeviceManager.cpp中。
BpServiceManager(const sp<IBinder>& impl)
: BpInterface<IServiceManager>(impl)
{
}
最终发现,其最初就是一个IServiceManager,先转成IBinder,再后面转回来而已。