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)就是造福,不是吗?^_^

© 2007, bigwhite. 版权所有.

Related posts:

  1. C++咬文嚼字-'Hijack const'
  2. C++咬文嚼字-'0 or NULL'
  3. C++ Advanced Training(二)
  4. C++ Advanced Training(一)
  5. APR源代码分析-设计篇