C++的类型转换 之 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>127int<-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 进行的是简单粗暴的转换,所以其正确性完全由程序员自己保证。

Creative Commons License Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 4.0 International license .