C++咬文嚼字-'Evil cast'
Cast也被称为"Explicit Type Conversion",即显式类型转换,在传统C中强制转型(cast)只有一种语法形式(T)e。Bjarne Stroustrup在'The Design and Evolution of C++'(以后称作D&E)一书的14.3小节开始就说了'无论是从语法还是从语义上, Cast都是C++里最难看的特征之一',所以他要为cast提供A New Cast Notation.
旧式的cast有诸多问题,在D&E一书中有描述,这里摘录一些:
首先记法(T)e单一,语义上容易引起错误,使人们很难理解代码的真实意图,几乎每种类型组合都有某种合法的解释:
如:const X* px = new X();
py = (Y*)px; //这里很难明确是去掉const,还是取得基类访问权或者是强制转型为其他unrelated类型的指针
其次(T)e记法上过渡使用'()',这使得在代码里难辨别是否为cast,并且很难用grep这样的搜索工具快速检索定位。
Bjarne Stroustrup引入几种cast operators实际上是对传统cast的一个细致分类,而且提供的这几种cast operators的功能的总和和传统cast功能一致,这也为C++程序员完全不使用传统cast提供了充分的理由。Scott Meyers在其'More effective c++'的item2中就明确说'Prefer C++ style casts'。新的cast operators使用了长名字和类似于模版的使用语法,也便于工具检索。
C++提供四种新式cast operator:
static_cast<T>(e)
dynamic_cast<T>(e)
reinterpret_cast<T>(e)
const_cast<T>(e)
我将这些C++ style cast支持常见的cast都融入到了下面这个例子中,慢慢体会吧:
#include <iostream>
class Base {
public:
int _x;
virtual int func() {;}
};
class Derived : public Base {
public:
int _y;
};
void print(char *str) {
std::cout << str << std::endl;
}
class T;
class S;
void test_reinterpret_cast(T *pt) {
S *ps = reinterpret_cast<S*>(pt);
}
int main() {
void *buf = 0;
//for static_cast
double d = 2007.02;
int i = 0;
char c = 'A';
i = static_cast<int>(d); //ok, static_cast支持non-pointer类型的conversion
std::cout << i << std::endl;
i = static_cast<int>(c); //ok, static_cast支持non-pointer类型的conversion
std::cout << i << std::endl;
int *p = 0;
buf = operator new(100);
p = static_cast<int*>(buf); //ok, static_cast支持从void*到任意指针类型
(*p) = 2008;
std::cout << *p << std::endl;
Base *pb = new Derived();
Derived *pd = static_cast<Derived*>(pb); //ok, static_cast利用静态类型信息完成类层次间的转型
pd->_y = 2009;
pd->Base::_x = 2010;
std::cout << pb->_x << std::endl;
std::cout << pd->_x << std::endl;
std::cout << pd->_y << std::endl;
pb = new Base();
pd = static_cast<Derived*>(pb); //ok, but pd is trivial and it is very dangerous to use it.
//pd->_y = 2011; //dangerous, may cause crash
//for const_cast
const int k = 2012;
//int m = const_cast<int>(k); //error: const_cast不支持non-pointer类型的conversion
const char* str = "hello";
//print(str); //error: invalid conversion from `const char*' to `char*'
print(const_cast<char*>(str));
//for dynamic_cast ,
//Base class should be a polymorphic class, otherwise the dynamic_cast operator will prevent you from doing cast
pb = new Derived();
pd = dynamic_cast<Derived*>(pb);
if (pd) {
std::cout <<"downcast ok\n"; //we will see this
} else {
std::cout <<"downcast error\n";
}
pb = new Base();
pd = dynamic_cast<Derived*>(pb);
if (pd) {
std::cout <<"downcast ok\n";
} else {
std::cout <<"downcast error\n"; // we will see this. dynamic_cast会在运行时利用运行时类型信息判断动态类型到底
是不是一个真实的Derived Object.
}
//for reinterpret_cast
char ch = 'A';
char *pch = &ch;
//int h = reinterpret_cast<int>(ch); // reinterpret_cast不支持这种non-pointer conversion
&nb
sp; int h = reinterpret_cast<int>(pch); //ok, reinterpret_cast支持这种将指针值转换成整数的conversion
std::cout << h << std::endl;
int *ph = reinterpret_cast<int*>(h); //ok, reinterpret_cast支持这种将任意整型数转换成地址的操作
//std::cout << *ph << std::endl; //may cause crash
//see test_reinterpret_cast function的定义, reinterpret_cast can
//converts any pointer type to any other pointer type, even of unrelated classes.
//and reinterpret_cast不需要知道类型的定义, 正如test_reinterpret_cast涉及到的
//M和T,在这里仅仅是两个forward declaration
}
Cast毕竟还是cast,依旧是很多Evil的源头,尽管C++做了细化和改善还是尽量少用的好,尽量减少cast的操作。总体来说Bjarne Stroustrup以及C++委员会的工作还是很有意义的。减轻罪恶(evil)就是造福,不是吗?^_^
评论