1 概念分析
static_cast
static_cast应该是适用范围最广的,适用于很多隐式转换,基类指针与子类指针的相互转换,或者添加const属性,去掉const属性应该用const_cast
double a = 10.23;
int b = static_cast<int>(a);
Base *ptr = new Child();
Child ptr2 = static_cast<Child*>(ptr);
const Base *ptr3 = static_cast<const Base*>(ptr)
但是需要注意的是,static_cast 在执行基类的指针转换为派生类的指针时( 即向下转型),此类转换并非始终安全。这时应该使用dynamic_cast,如果是向上转型,则两者效果相同。
dynamic_cast
dynamic_cast转换符只能用于指针或者引用。dynamic_cast转换符只能用于含有虚函数的类。dynamic_cast转换操作符在执行类型转换时首先将检查能否成功转换,如果能成功转换则转换之,如果转换失败,如果是指针则反回一个0值,如果是转换的是引用,则抛出一个bad_cast异常,所以在使用dynamic_cast转换之间应使用if语句对其转换成功与否进行测试,比如pd = dynamic_cast(pb); if(pd){…}else{…},或者这样测试if(dynamic_cast(pb)){…}else{…}。
Base *ptr = new Base();
Child * ptr2 = dynamic_cast<Child*>(ptr);
if(!ptr2)
cout<<error;
ptr指针指向的是基类,转化为子类指针肯定会引发问题,所以这个时候我们应该使用dynamic_cast进行检查,这样可以避免盲目转换。
const_cast
用来将对象的常量性去除
reinterpret_cast
它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值),或者把一种指针转为另一种指针。
2 实例分析
class A
{
public:
virtual void foo() { }
};
class B
{
public:
virtual void foo() { }
};
class C : public A , public B
{
public:
virtual void foo() { }
};
void bar1(A *pa)
{
B *pc = dynamic_cast(pa);
}
void bar2(A *pa)
{
B *pc = static_cast(pa);
}
void bar3()
{
C c;
A *pa = &c;
B *pb = static_cast(static_cast(pa));
}
A bar1无法通过编译
B bar2无法通过编译
C bar3无法通过编译
D bar1可以正常运行,但是采用了错误的cast方法
static_cast和dynamic_cast都是用于强制类型转换。dynamic_cast是在运行时遍历继承树,所以,在编译时不会报错。但是因为A和B无关,所以运行时报错,那么A和D都是错误的。static_cast:编译器隐式执行的任何类型转换都可由它显式完成。
其中对于:
(1) 基本类型。如可以将int转换为double(编译器会执行隐式转换),但是不能将int*用它转换到double*(没有此隐式转换)。
(2) 对于用户自定义类型,如果两个类无关,则会编译出错(所以B正确),如果存在继承关系,则可以在基类和派生类之间进行任何转型,在编译期间不会出错。所以bar3可以通过编译(C选项是错误的)。