C++中的转型操作符
旧式的C转型方式,几乎允许你将任何类型转换为任何其它类型,有其自身的缺陷,表现在以下两方面:
1.不能更精确地指明其转型的意图。
如将一个pointer-to-base-class-object转型为一个pointer-to-derived-class-object(改变一个对象的类型)和将一个pointer-to-const-object转型为一个pointer-to-non-const-object(改变对象的常量性),在旧式C语法中并不区分。
2.难以辨识。
旧式C转型方式的语法为(type)expression,由一对小括号加上一个对象名称组成,而这种语法结构在C++的任何地方都有可能使用,这就无法很直观地判断出是否是转型操作。
———————————————————分隔符—————————————————
为解决上述的缺点,C++引入4个新型转型操作符,分别为:
static_cast, const_cast, dynamic_cast, reinterpret_cast
语法为: ***_cast<type>(expression)
下面着重解释四个新型操作符的用途:
一.static_cast: 基本与拥有与C旧式转型相同的威力与意义,以及相同的限制。如:
//计算两个int型数相除,结果为double型
int firstNum,secondNum;
double res =(double)firstNum / secondNum; //旧式C语法
double res =static_cast<double>(firstNum) / secondNum; //新式C++转型符
二.const_cast: 用来改变表达式中的常量性(constness)或易变性(volatileness)。如:
int num;
const int *cpNum =#
int *pNum =cpNum; //error:cannot convert from 'const int *' to 'int *'
int *pNum = (int *)cpNum; //旧式C
int *pNum =const_cast<int *>(cpNum); //新式C++const_cast移除常量性
三.dynamic_cast: 用来执行继承体系中“安全的向下转型或跨系转型动作”。如:
可以利用dynamic_cast将“指向base class object 的pointer或reference”转型为“指向derived class object的pointer或reference”
如果转型失败,会以一个null指针或一个exception 表现出来(指针转型失败返回null,引用转型失败抛出异常)
class CBase { };
class CDerived:public CBase { };
CDerived dc;
CDerived *dp =&dc;
CBase *bp =dynamic_cast<CBase *>(dp); //使用dynamic_cast将指向继承类的指针转化为指向基类的指针
CBase &br =dynamic_cast<CBase &>(dc); //使用dynamic_cast将指向继承类的引用转化为指向基类的引用
四.reinterpret_cast: 最常用的用途是转换"函数指针"类型。如:
typedef void(*funcPtr)(); //funcPtr是个无参数返回值为void型的函数指针类型
int iFunc(){return0;} //iFunc为一个无参数返回值为int型的函数
void func(funcPtrf){} //func函数的参数是一个类型为funcPtr类型的函数指针
main()
{
func(iFunc()); //error:cannotconvert parameter 1 from 'int' to 'void (__cdecl *)(void)'
func(reinterpre_cast<funcPtr>(iFunc); //right!reinterpre_cast将返回值为int 的函数转化为 返回值为void的函数
}
五.补充及修正:
1.static_cast与dynamic_cast
Static_cast 常用于数据类型之间的转换,它也可以实现dynamic_cast中的转换效果,当实现上行转换(继承类转换基类)时,二者可以实现相同的转换效果,当实现下行转换(基类转继承类)时,由于static_cast没有动态类型检查机制,转换可能不安全。而正是由于static_cast不作类型检查,它的转换比dynamic_cast要快。
2. reinterpret_cast
reinterpret_cast字面意思是重新解释,主要是将数据从一种类型的转换为另一种类型。所谓“通常为操作数的位模式提供较低层的重新解释”也就是说将数据以二进制存在形式的重新解释。
int i;
char *p = "Thisis a example.";
i =reinterpret_cast<int>(p);
此时结果,i与p的值是完全相同的。reinterpret_cast的作用是说将指针p的值以二进制(位模式)的方式被解释为整型,并赋给i,一个明显的现象是在转换前后没有数位损失。
因此,reinterpret_cast允许转换一个指针为其他类型的指针,也允许将一个指针转换为整数类型,反之亦然。这个操作符能够在非相关的类型之间进行转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝,在类型之间指向的内容不做任何类型的检查和转换。这是一个强制转换。使用时有很大的风险,慎用之。比如:
class A { public:int m_a; };
class B { public:int m_b; };
class C : public A,public B {};
那么对于以下代码:
C c;
printf("%p, %p,%p\r\n", &c, reinterpret_cast<B*>(&c), static_cast<B*>(&c));
前两个的输出值是相同的,最后一个则会在原基础上偏移4个字节,这是因为static_cast计算了父子类指针转换的偏移量,并将之转换到正确的地址(c里面有m_a,m_b,转换为B*指针后指到m_b处),而reinterpret_cast却不会做这一层转换。
因此, 你需要谨慎使用 reinterpret_cast.