mingminglulu 发表于 2004-11-15 12:55:00 C++ 引入了 const_cast, reinterpret_cast 之类的新的显式类型转换方式,不仅大多数 C 程序员觉得不是很习惯,就连某些有经验的C++ 程序员都会在一些细节上犯错。诚然,既然我们可以简单的写出: int i = (int)p;// p is a pointer 这样的显式转换,为什么还要使用 int i = reinterpret_cast<int>( p ); 这么复杂的形式呢? 这篇文章的目的是简单介绍 C++ 的类型转换系统,并对使用和扩展进行一些讨论。 C++ 引入了 const_cast, reinterpret_cast 之类的新的显式类型转换方式,不仅大多数 C 程序员觉得不是很习惯,就连某些有经验的C++ 程序员都会在一些细节上犯错。诚然,既然我们可以简单的写出: int i = (int)p;// p is a pointer 这样的显式转换,为什么还要使用 int i = reinterpret_cast<int>( p ); 这么复杂的形式呢? 这篇文章的目的是简单介绍 C++ 的类型转换系统,并对使用和扩展进行一些讨论。 1. 为什么需要类型转换? char c = 'a'; 通常,隐式转换意味着编译器认为你的转换是合理的或者是安全的;显式转换意味着编译器能够找到一个转换方式,但是它不保证这个转换是否安全,所以需要程序员额外指出;而无法转换则意味着编译器无法发现一条直接的路径来进行类型转换。 2. 为什么需要 C++ 风格的显式转换? const char* s = 0; 这一句语句,不仅转换了类型,还把 const 也去掉了。通常如果我们看到一句游离的显式转换,我们不能立即知道作者的意图,这也为今后的错误埋下了伏笔。C++ 风格的现实转换通过区分各种转换情况来增加安全性:通过 const_cast 来取消 const、volatile 之类的修饰,通过 static_cast 来做相关类型的转换,通过 reinterpret_cast 来做低级的转换,...。有一个例子可以说明这些转换的“精确”程度: class Interface class Base {}; class Derived : public Interface, public Base {}; int main() 这段代码中,两个 cast 都是合法的,但是意义不同。前者意味着“把 b 的指针的值直接赋给 d1,并且把它作为 Derived 类型解释”,后者意味着“根据相关类型信息来做转换,如果可能,对 b 指针做一些偏移”。在上面这个例子里面,d1 和 d2 是不相等的!可能由于很多书上都说:如果你要在指针之间互相转换,应该使用 reinterpret_cast,所以不少程序员使用 reinterpret_cast 来做一切指针类型转换,虽然通常他们不会得到错误,但是的确是不小的隐患。 本来我这个例子的黑体部分使用的是0,有一位网友指出,C++在进行cast的时候会对0进行特殊处理。也就是说,在上面的例子中,如果使用0,那么d1和d2是一样的。 3. 一些例子 (1) itf_cast IPersistFile* pPersistFile; 这段代码很简单但是不够直接,所以我们可以实现这样一个函数: template<typename T1, typename T2> 然后我们可以把上面的语句写成 pPersistFile = itf_cast( pHtmlDocument ); 这非常的直观。仔细的读者可能会发现 __uuidof 不是标准的 C++ 所定义的,而是 VC 的一个扩展。事实上,在这里你可以用 traits 很简单的实现同样的功能。 (2) stream_cast template<typename T1, typename T2> 这样一来,你可以用以下语句进行转换: string s("0.5"); (3) safe_cast template<typename T1, typename T2> 于是,stream_cast<char>(1000); 这样的语句就会抛出异常。
************************************************************************
static_cast VERSUS reinterpret_cast
static_cast 和 reinterpret_cast 操作符修改了操作数类型. 它们不是互逆的; static_cast 在编译时使用类型信息执行转换, 在转换执行必要的检测(诸如指针越界计算, 类型检查). 其操作数相对是安全的. 另一方面, reinterpret_cast 仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换, 例子如下: int n=9; double d=static_cast < double > (n); 上面的例子中, 我们将一个变量从 int 转换到 double. 这些类型的二进制表达式是不同的. 要将整数 9 转换到 双精度整数 9, static_cast 需要正确地为双精度整数 d 补足比特位. 其结果为 9.0. reinterpret_cast 的行为却不同: int n=9; double d=reinterpret_cast<double & > (n); 这次, 结果有所不同. 在进行计算以后, d 包含无用值. 这是因为 reinterpret_cast 仅仅是复制 n 的比特位到 d, 没有进行必要的分析. 因此, 你需要谨慎使用 reinterpret_cast. ------------------------- Danny Kalev |