分类: C/C++
2013-12-27 21:57:22
C++有四种转型操作符,以下小结一下:
1,static_cast<>()
用得最多的,如果转换的是类型,则调用转型函数:比如int转float,float转int等基本数据类型的转型,如果是一个类,就调用类型转换函数,比如:
#include
using namespace std;
class A
{
public:
explicit A(int _a = 0) : a(_a) {}
operator int() const
{
return a;
}
private:
int a;
};
int main()
{
A a(100);
int b = static_cast(a);
cout< system("PAUSE");
return 0;
};
可以转换一个基类指针到子类指针的转型,但是不做动态类型检查,可以不存在虚函数,因此转型可能是不安全的,但是是快速的。
2,dynamic_cast<>()
专门用于C++类的指针转型,且是用于多态继承体系中的类。public继承体现了‘is-a’的类关系,一个基类指针,可以指向子类对象,它的子类类型是动态类型,dynamic_cast<>()就是将基类指针转型成它动态类型的子类指针,如果类型不对,结果就是空。
#include
using namespace std;
class B
{
public:
virtual void foo() {
cout<<"B.foo"<}
};class D1 : public B
{
public:
void foo() {
cout<<"D1.foo"<}
void foo2() {
cout<<"D1.foo2"<}
};class D2 : public B
{
public:
void foo() {
cout<<"D2.foo"<}
void foo3() {
cout<<"D2.foo3"<}
};
int main()
{
B *pb = new D2;
pb->foo();
D1 *pd1 = dynamic_cast(pb);
if(pd1)
{
pd1->foo2();
}
D2 *pd2 = dynamic_cast(pb);
if(pd2)
{
pd2->foo3();
}
delete pb;
system("PAUSE");
return 0;
};
(1)必须有虚接口,那么,如果用基类指针使用虚接口,则可以动态绑定,不需要转型,就能体现多态;(2)如果是子类指针,可以直接给基类指针,可以直接使用。所以使用dynamic_cast的情形比较简单,就是用基类指针使用非虚接口的情形。非虚接口体现了子类的特有操作,也就是要确定它的动态类型,如上例,给了pb指针,但不知道是D1还是D2,转型后,看结果是否非空,如果空则表示不是这个类型,然后分情况处理。它相当于使用typeid+static_cast,是安全的转型。
3,const_cast<>()
用以去掉‘数据’的常量属性,常量属性多体现在指针和引用,因为如果没有指针和引用,就不存在不小心修改了不能修改的东西。如
const int a =314;
a=2;//这个傻瓜编译器都知道你在忽悠它
int *p = &a;
*p=3;//这两句,是不是可以成功忽悠你,转了弯修改了不能修改的东西C++会报错,因为&a是const int *,不能将一个const指针或引用赋给指针或初始化引用。换成这样就行了:
int *p=const_cast
(&a);
编译器放给了你这样的权力,如果你这样写,表明你能为它的后果负责,如果出了错,如果你做的是导弹火控系统,你将会知道结果有多严重。
MSDN里有一个例子,一个const成员函数里修改this指针的常量性,这很高明,真的很高明,因为完全没有理由使用mutable关键字啦~~const成员函数的第一个参数类型是const ClassName*,简单的不同。
4,reinterpret_cast
这个我用得非常少,因为太长了,每次打都不记得。字面意思是重新解释,就是可以将任何指针转型成其它指针或者整型类型,它是底层的转型,也是不安全的。MSDN里有一个hash函数的例子比较‘高层’的运用了它。哦,对了,它不能去掉const属性。
给一个我的例子,功能是显示数据的每一个字节:
#include
#includeusing namespace std;
template
class for_byte
{
public:
template
void operator()(T & data)
{
unsigned char * p = reinterpret_cast(&data);
for(int i=sizeof(T);i>0;--i)
{
fun(*p++);
}
}
private:
Functor fun;
};struct display_bit
{
void operator()(unsigned char byte)
{
printf("%02X",byte);
}
};int main(int argc, char *argv[])
{
for_bytedisplay;
double x = 3.14;
int y = -1;
display(x);
printf("/n");
display(y);
printf("/n");
display(display);
printf("/n");
system("PAUSE");
return EXIT_SUCCESS;
}
补充1:
旧的C风格转型几乎允许你把任何类型转换成任何其他类型(当然有些限制)
由于他的功能太强大,对于程序员阅读这样的程序会带来很大的识别障碍
几乎所有的工作都用(type)expression的方式进行转换
为此C++提供了4种新的转型操作符号(cast operation)
static_cast, const_cast, dynamic_cast和reinterpret_cast
1.static_cast
static_cast基本拥有c风格转型差不多的功能,和相同的限制。比如int向double的转换
int testNum;
static_casttestNum;
同样你也不能将int或者struct转换成pointer,这个转换在c里面也是不允许的
值得注意的是static_cast不支持const向non-const的互相转换,就是说不能排除表达式的常量性
const_cast负责这一功能
2.const_cast
const_cast专注于这一功能,应用面很狭窄,大使增加了可读性。
class A{...}
class AB:public A{...}
void Update(AB* xy);
AB ab;
const AB& cab = ab;
Update(&cab);//这样是错误的
Update(const_cast(&cab));//正确,去掉了常量性
但是 const_cast不支持带有继承关系的转换
A* pa = new AB;
Update(const_castpa);//这样是错误的
现在我只需要记住。const_cast最重要的作用就是去除常量性3.dynamic_cast
用来执行继承体系中安全的向下转型或者跨系转换,上面的操作用dynamic_cast是可以支持的
A* pa = new AB;
Update(dynamic_castpa);
注意的是关于此操作符的返回值
如果表达式是pointer ,转换失败的话会得到一个NULL
如果............是ref ,........................会抛出一个异常
dynamic_cast只能做这一类型的转换,请不要尝试去用dynamic_cast改变表达式的常量性,也无法在缺乏虚函数的型别上使用(比如int to double,这样的转换得使用static_cast)
4.reinterpret_cast
这个我了看的不是很透,资料上说与编译环境相关,不具备移植性。
他最常用途是转换(函数指针)的型别
有一个保存函数指针的数组,里面指针指向函数的return 都是void
但是你现在有个函数return为int,这个时候如果你想把这个函数放进funcPtrArray
如果没有转型是可能实现的
typedefine void (*FuncPtr())
int func();
funcPtrArray[0] = &func;//错误,型别不对
funcPtrArray[0] = reinterpret_cast(FuncPtr)(&func);//正确
补充2:
C++通过引进四个新的类型转换操作符克服了C风格类型转换的缺点,这四个操作符是:
const_cast
( expression ) dynamic_cast
( expression ) static_cast
( expression ) reinterpret_cast
( expression ) 在大多数情况下,对于这些操作符你只需要知道原来你习惯于这样写:
(type) expression
而现在你总应该这样写:
static_cast(expression)
例如,假设你想把一个int转换成double,以便让包含int类型变量的表达式产生出浮点数值的结果。如果用C风格的类型转换,你能这样写:
int firstNumber, secondNumber;
...
double result = ((double)firstNumber)/secondNumber;
如果用上述新的类型转换方法,你应该这样写:
double result = static_cast
(firstNumber)/secondNumber; 这种形式十分容易被辨识出来,不论是对人类还是对工具程序而言。
这四个转型操作符各司其职:
l const_cast 通常用来将对象的常量性转除(cast away the constness)。它是唯一有此能力的C++-style转型操作符。
l dynamic_cast用来执行继承体系中安全的向下转型或跨系转型动作。也就是说你可以利用它将指向基类对象的指针或者引用转型为指向派生类对象的指针或引用,并得知转型是否成功。如果转型失败,会以一个null指针(当转型对象是指针)或一个exception(当转型对象是引用)表现出来。dynamic_cast是唯一无法由旧式语法执行的转型动作,也是唯一可能消耗重大运行成本的转型动作。
l static_cast 基本上拥有与C旧式转型相同的威力与意义,以及相同的限制。例如将一个非 const 的对象转换为 const 对象,或将int转换为 double等等。它也可以用来执行上述多种转换的反向转换,例如将void*指针转为typed指针,将pointer-to-base转为pointer-to-derived。但是他无法将const转为non-const,这个只有const-cast才能够办到。
l reinterpret_cast意图执行低级转型,实际动作及结果可能取决于编译器,这也就表示它不可移植。例如将一个pointer to int 转型为int。这一类转型在低级代码以外很少见。
旧式转型在 C++ 中仍然是合法的,但是这里更推荐使用新形式。首先,它们在代码中更加易于辨认(不仅对人,而且对 grep 这样的工具也是如此),因而得以简化“找出类型系统在哪个地点被破坏”的过程。第二,各转型动作的目标愈窄化,编译器愈可能诊断出错误的运用。例如,如果你打算将常量性去掉,除非使用新式转型中的const_cast,否则无法通过编译。