C++ 的类型转换 之 static_cast
On 2011-03-02 22:57:00 By SoliC++的类型转换 之 static_cast
static_cast 一般用来将枚举类型转换成整型,或者整型转换成浮点型。也可以用来将指向父类的指针转换成指向子类的指针。做这些转换前,你必须确定要转换的数据确实是目标类型的数据,因为 static_cast 不做运行时的类型检查以保证转换的安全性。也因此, static_cast 不如 dynamic_cast 安全。对含有二义性的指针, dynamic_cast 会转换失败,而 static_cast 却直接且粗暴地进行转换。这是非常危险的。
比如:
class B {};
class D : public B {};
void f(B* pb, D* pd) {
D* pd2 = static_cast<D*>(pb); // Not safe, D can have fields
// and methods that are not in B.
B* pb2 = static_cast<B*>(pd); // Safe conversion, D always
// contains all of B.
}
上面的第一个类型转换是不安全的。比如,一旦使用 pd2 调用了一个子类 D 有而父类 B 没有的方法,则程序就会因越界访问而崩溃。
static_cast 和 dynamic_cast 都可以用于类层次结构中基类和子类之间指针或引用的转换。所不同的是,static_cast 仅仅是依靠类型转换语句中提供的信息(尖括号中的类型)来进行转换;而 dynamic_cast 则会遍历整个类的继承体系进行类型检查。比如:
class B {
public:
virtual void Test(){}
};
class D : public B {};
void f(B* pb) {
D* pd1 = dynamic_cast<D*>(pb);
D* pd2 = static_cast<D*>(pb);
}
如果 pb 确实是指向一个 D 类型的对象,那 pd1 和 pd2 的值是相同的,即使 pb 为 NULL 。
如果 pb 实际指向的是一个 B 类型的对象,那 dynamic_cast 就会转换失败,并返回 NULL (此时 pd1 为 NULL );而 static_cast 却依据程序员指定的类型简单地返回一个指针指向假定的 D 类型的对象(此时 pd2 不为 NULL ),这当然是错误的。
static_cast 还可以在两个类对象之间进行转换,比如把类型为 A 的对象 a,转换为类型为 B 的对象。如下:
class A;
class B;
A a;
B b;
b = static_cast<B>(a);
此过程可以看做是以 a 为参数构造一个 B 类型的临时对象,然后再把这个临时对象赋值给 b 。如下:
class A;
class B;
A a;
B b;
B c(a);
b = c;
所以,如果让以上代码通过编译,那么 B 类必须含有以 A 类的对象(或对象的引用)为参数的构造函数。如下:
B(A& a)
{
// ...
}
这实际上是把转换的工作交给构造函数去做了。
static_cast 最常用的是基本类型直接的转换,比如 char 与 int 、 int 与 float 、 enum 与 int 之间的转换。在把 int 转换为 char 时,如果 char 没有足够的比特位来存放 int 的值( int>127
或 int<-127
时),那么 static_cast 所做的只是简单的截断,及简单地把 int 的低 8 位复制到 char 的 8 位中,并直接抛弃高位。在把 int 转换为 enum 时,如果 int 的值没有落进 enum 的范围内,则 enum 的值将是“未定义”的。比如,定义一个枚举类型 Week,它包含周一到周日七天:
enum Week
{
Monday = 1,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
};
此时如果把值为 8 的 int 转换为 week 类型,那么这个 Week 变量不会是周一到周日的任何一天。
Week noday = static_cast<Week>(8);
如果你用 %d
格式把它打印出来,你会发现,它的值确实是 8。但这已经超出周一到周日了。世界上没有“星期八”,不是吗?
static_cast 甚至可以把任何一个表达式转换为 void 类型。
再次提醒,static_cast 完全靠程序员自己去保证转换的正确性。
static_cast 转换的目标类型可以带 const 、 volatile 或 __unaligned 属性。但 static_cast 不能把源类型的这些熟悉移除。如果想强制移除一个变量的 const 、 volatile 或 __unaligned 属性,请参考 const_cast 操作符。
小结一下:
static_cast 常用来进行基本类型直接的转换,如 char 与 int 、 int 与 float 、 enum 与 int 之间;
static_cast 也可以转换用户自定义类型,但目标类型必须含有相应的构造函数;
static_cast 还可以转换对象的指针类型,但它不进行运行时类型检查,所以是不安全的;
static_cast 甚至可以把任何表达式都转换成 void 类型;
satic_cast 不能移除变量的 const 属性,请参考 const_cast 操作符;
static_cast 进行的是简单粗暴的转换,所以其正确性完全由程序员自己保证。