优先使用 C++ 风格类型转换

大多数程序员都认为 C++ 是在 C 的基础上引入面向对象概念。这一观点并不完全准确。C 语言是一中简洁优雅的语言,若仅仅引入面向对象概念,由怎么会有众多编写 C++ 的大师认为自己对 C++ 的了解并不深呢?可想而知,C++ 比单纯的 “C 语言 + 面向对象” 还要更复杂得多。

C++ 在设计的时候同样也考虑到程序设计过程中的类型转换问题,但C语言风格的类型转换对于 C++ 来说过于简单粗暴(通过括号及目标类型来进行转换)。试想想,C 中只有基本数据类型以及用户自定义的 struct 结构,因此这样“简单粗暴”的类型转换对C来说是足够,但对引入面向对象之后的 C++ 却不然,至少 C++ 还有着无数程序员自定义的类。因此 C++ 也拥有自己的类型转换操作符。

除了上面所说的原因,还有另一个优先使用C++ 风格类型转换操作符的原因是 C 风格的类型转换不利于程序员或查找工具查找,人工查找本身就比较容易出错,而使用查找工具查找又如何?一个稍微大一些的程序,总会有许许多多的括号出现,要准确地定位到程序代码中何处使用了类型转换,恐怕使用查找工具也难以查找。

C++ 一共提供了四种类型转换操作符:

  1. static_cast<type>(expression);
  2. const_cast<type>(expression);
  3. dynamic_cast<type>(expression);
  4. reinterpret_cast<type>(expression);

C 风格是这么写: (type) expression; .从今起,C++ 应该这么写: static_cast<type> (expression);

这样的写法无论从人工审查或者是查找工具查找都更便于前者。

下面对C++ 提供的四种类型转换做一些介绍:

static_cast 操作符的功能和 C 语言的类型转换功能一样,而且有着同样的功能局限,例如不能将 struct 类型转换成 int 类型,等等。同时 static_cast 操作符也不能去除变量的 const 属性。范例代码:

int input_data = 12345;
double data = static_cast<double>(input_data);

和 C 风格类型转换不同的饿时, static_cast 不能移除类型的 const 属性。 const_cast 操作符,正好弥补了移除 const 属性这一问题。 const_cast 能够换掉类型的 constvolatileness 属性。从下面的代码,可以看出 const_cast 的用法

class CIndexObject{...};
class CDNA: public CIndexObject{...};
void update(SpecialWidget * psw);
SpecialWidget sw;
const SpecialWidget& csw = sw;
update(&csw);
update(const_cast<SpecialWidget*>(&csw));
update((SpecialWidget*) &csw);

这里的 update(&csw) 是错误的,因为 update 参数是不带 const 属性; update(const_cast<SpecialWidget*>(&csw)); 使用了 C++ 风格类型转换,换掉了 cswconst 属性; update((SpecialWidget*) &csw); 使用了 C 语言风格的类型转换,同样换掉了 cswconst 属性。 const_cast 操作符只能用在影响 constnessvolatilness 地方上,不能永在向继承子类进行类型转换,所以以下的语句也是错误的。

Widget *pw = new SpecialWidget;
update(const_cast<SpecialWidget*> (pw));

第三种类型转换是 dynamic_cast 操作符。 dynamic_cast 是用于安全地沿着类的继承关系向下进行类型转换。这也就是说 dynamic_cast 可以把指向基类的指针或引用转换为指向其派生类的指针或引用。

使用 dynamic_cast 进行类型转换的同时还可以知道转换是否成功,转换失败的时候,返回空指针或者抛出异常(指针转换失败返回空指针,引用转换失败抛出异常)。

dynamic_cast 类型转换是有限制的,它不能被用在缺乏虚函数的类型上。以下是 dynamic_cast 的例子:

class CIndexObject{...};
class CDNA: public CIndexObject{...};
CIndexObject indexObject;
CDNA dna(CGAT);
indexObject = dynamic_cast<CIndexObject>(dna);

最后一种类型转换是 reinterpret_cast 操作符。这个操作符在不同编译器环境有不同的实现,并且转换结果几乎是在运行期定义的,所以代码不利于移植,在此不做讨论。

小结

  1. 使用 C++ 风格类型转换的好处:安全,便于查找。
  2. 普通类型转换使用 static_cast 。
  3. 移除const 和 valatileness 属性可以使用 const_cast 。
  4. 在同一继承树上的类向下(向基类)转换使用 dynamic_cast 。
  5. 使用 reinterpret_cast需谨慎。