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

精灵发威,巴萨险平

相信在今天之前巴萨的球迷都很失落,因为巴萨在冠军杯八强战中被红魔利物浦淘汰了。但是看了今晨的'西班牙国家Derby',相信大家心情会略为好转起来,虽然巴萨依然没有赢球,让我们欣喜的是看到了一位潜在的巴萨未来王者的表演。

近期巴萨的境况不好,内部不团结等等因素让球队的战绩和上个赛季相比不能同日而语,昔日那个巴萨梦之队似乎渐渐从人们的眼线里消失了。今晨同样是从冠军杯被淘汰的两支西甲豪门相遇了,巴萨对皇马,在西班牙足球界,这丝毫不亚于火星撞地球^_^。巴萨境遇不好,皇马则更加落魄,上亿欧元打造的豪华军团,现在细数数皇马全队居然没有了领军人物,也就是劳尔资格老些,勉强撑得起门面,想当年齐达内、肥罗,菲戈、贝克汉姆等多位世界足球先生,欧洲足球先生坐镇的日子已经一去不复返了。皇马目前也仅剩下一个空架子罢了,用俗话说就是有些散。历史上特别是最近几年西班牙德比都甚是好看,每场都堪称经典,精彩进球也比比皆是,平均每场进球数是不少。这次估计也会延续这一势头的。

说实话我是没有看全所有比赛,但是几个进球还是在体育新闻中一个没拉下的全看到了。当梅西从右路推射远角入网扳平比分的时候人们也许只是认为这个小精灵状态很好;当梅西中路捡漏并打入一粒精彩的凌空抽射时,人们也许也只是为精灵的球技而鼓掌;当梅西从左路接小罗传球,利用个人技术快速突破多个后卫阻截并在后卫出脚拦截前将球从禁区左肋12码处打入时,人们开始惊叹今天的诺坎普王者诞生了,而这时时钟已经指向开场89分钟了。留着这位精灵的时间已经没有了。三次落后,三个从不同方向摄入的精彩进球扳平比分,相信所有人都会把自己打的最高分送给这个来自潘帕拉高原的精灵-梅西

没人会否认梅西会成为未来巴萨的新的领军人物,在巴萨目前这个动荡期,在有传闻说小罗即将出走的这个时候,人们会给梅西更多的期待和鼓励,加油吧,小伙子。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats