fatalerror99
fatalerror99的公告
Copyleft © 2005 - 2008 by fatalerror99 (iTePub's Nirvana)

本 BLog 所有文章除注明转载者外,均为本人原创或翻译,欢迎转载。转载时请保持文章完整并注明出处。

强烈推荐使用 Mozilla Firefox 浏览本 BLog。

MSN: fatalerror9999@hotmail.com

e-mail: kong_kong@163.com

最近评论
fatalerror99:楼上说得对,原来的翻译确实错了,而且 object 应该都是单数,不是复数。
jjy:"每一件适用于 B objects(对象)的事情也适用于 D objects(对象),因为每一个 D objects 都 is-a(是一个)D objects(对象);" 应该是"因为每一个 D objects 都 is-a(是一个)B objects(对象);""
jjy:"一旦 derived class destructor(派生类析构函数)运行,这个 object(对象)的 derived class data members(派生类数据成员)就呈现为未定义的值,所以 C++ 就将它们视为不再存在。"
应该是base class destructor运行时...
七星瓢企鹅:央视的新楼盖起来了,听说北京人照例给他起了个外号叫“大裤衩”
mopyman:严重鄙视此人
turingbook
简直是利欲熏心
文章分类
收藏
    相册
    Effective C++, 3rd Edition 插图
    数学公式
    不服不行
    Bjarne Stroustrup
    Alexander A. Stepanov
    Andrei Alexandrescu
    Bruce Eckel
    Charles Petzold
    Chris Sells
    David R. Musser
    Dennis M. Ritchie
    Donald E. Knuth
    Herb Sutter
    James Gosling
    Nicolai M. Josuttis
    Scott Meyers
    Stanley B. Lippman
    侯捷
    荣耀
    精点 BLog
    水瓶水蓝
    水瓶水蓝 —— 晃荡在阴阳两界的魂儿
    (RSS)
    CityLife 的流水账(RSS)
    为艺术而技术(RSS)
    乱发当风(RSS)
    微起涟漪 —— basse(RSS)
    暗金色月亮的赫拉迪克宝盒(RSS)
    杏坛雨的博客(RSS)
    王晓渔:书中自有……(RSS)
    开发 BLog
    alai04 的专栏(RSS)
    C++ 的罗浮宫(RSS)
    Coofucoo's Blog--The Unadulterated Coofucoo(RSS)
    GreenCode's Blog(RSS)
    ilovevc 的专栏(RSS)
    lxwde 的专栏(RSS)
    oiramario(RSS)
    ralph623 的专栏(RSS)
    renco 的专栏(RSS)
    Scorpio Auding @ Blog++(RSS)
    SnowFalcon 的专栏(RSS)
    Stan Lippman's BLog(RSS)
    Sutter's (Online) Mill(RSS)
    切尔斯基(RSS)
    周星星 之 Blog(RSS)
    孟岩(RSS)
    开心就好的代码人生(RSS)
    心如止水 —— coofucoo 的专栏(RSS)
    方舟(RSS)
    歌谣在风中飘舞(RSS)
    空谷幽兰,心如皓月 —— 陈皓专栏(RSS)
    艺术编程(RSS)
    透明思考 - 1(RSS)
    透明思考 - 2(RSS)
    陈硕的 Blog(RSS)
    开发网站
    CSDN.NET
    artima devdloper: Best practices in enterprise software development
    Experts Exchange
    IBM DeveloperWorks
    IBM DeveloperWorks 中国(RSS)
    Programmers' Heaven
    The Artima Developer Community
    The Code Project
    卡卡社区
    开发语言与环境
    (CHEZ (CHEZ SCHEME))
    .NET Languages
    PHP: Hypertext Preprocessor
    Eclipse.org home
    Python Programming Language
    REBOL Technologies
    ActiveState
    D Programming Language
    Eclipse Plugins
    Eclipse Plusin Central
    Eiffel Software
    GCL - GNU Common Lisp
    GNU Compiler Collection (GCC)
    Groovy
    IronPython
    Perl
    Ruby on Rails
    Ruby Programming Language
    The Programming Language Lua
    坛子若干
    iTePub
    自由小店 —— iTePub 共建共享电子图书交互平台
    (RSS)
    ChinaJavaWorld.com 技术论坛
    ChinaUnix
    CSDN 技术社区 —— 这个不说大家也知道
    Huihoo - Open Source Community
    ITPUB 论坛
    卡卡社区
    网络书店
    Amazon.com
    China-Pub 网上书店
    joyo Amazon 卓越亚马逊
    第二书店
    有一杯咖啡叫做 Java
    Hibernate
    Java Technology
    JavaWorld
    jGuru
    Spring Framework
    The Apache Software Foundation
    TheServerSide.COM: Your Enterprise Java Community
    有一部经典叫做 C++
    Boost C++ Libraries
    C Programming and C++ Programming
    C/C++ Reference
    cplusplus.com
    Programming in C++, Rules and Recommendations
    The ADAPTIVE Communication Enviroment (ACE)
    The C Standards Committee (ISO C)
    The C++ Standard Committee (ISO C++)
    有一只企鹅叫做 Linux
    Debian
    Fedora Project
    Linux Journal
    Linux Online!
    Linux 伊甸园
    Linux.com
    Red Hat
    SUSE Linux Enterprise from Novell
    The Linux Foundation
    The Linux Kernel Archives
    Ubuntu
    有一种自由叫做开源
    OpenBSD
    CodeGuru
    FreeBSD
    FSF - The Free Software Foundation
    GNU
    Huihoo - Open Source Community
    Open Source Initiative (OSI)
    OpenSolaris
    SourceForge.net
    The Open Enterprise Foundation (OEF)
    专业出版机构
    Addison-Wesley
    APress
    Manning Publications Co.
    McGraw-Hill
    O'Reilly
    Prentice Hall PTR
    Wiley
    Wordware Publishing, Inc.
    Wrox
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    翻译 [翻译] Effective C++, 3rd Edition, Item 27: 最少化 casting(强制转型)(上)收藏

    新一篇: [翻译] Effective C++, 3rd Edition, Item 27: 最少化 casting(强制转型)(下) | 旧一篇: [翻译] Effective C++, 3rd Edition, Item 26: 只要有可能就推迟 variable definitions(变量定义)

    Item 27: 最少化 casting(强制转型)

    作者:Scott Meyers

    译者:fatalerror99 (iTePub's Nirvana)

    发布:http://blog.csdn.net/fatalerror99/

    C++ 的规则被设计为保证不会发生类型错误。在理论上,如果你的程序想顺利地通过编译,它就不应该试图针对任何 objects 做任何不安全的或无意义的操作。这是一个非常有价值的保证,你不应该轻易地放弃它。

    不幸的是,casts(强制转型)搅乱了 type system(类型系统)。它会导致各种各样的麻烦,其中一些容易被察觉,另一些则格外地微妙。如果你从 C,Java,或 C# 转到 C++,请一定注意,因为 casting(强制转型)在那些语言中比在 C++ 中更有必要,危险也更少。但是 C++ 不是 C,也不是 Java,也不是 C#。在这一语言中,casting(强制转型)是一个需要你带有极大的敬畏之心才可以靠近的特性。

    我们就从回顾 casting(强制转型)语法开始,因为对于同样的 cast(强制转型)通常有三种不同的写法。C-style casts(C 风格强制转型)如下:

    (T) expression                      // cast expression to be of type T

    Function-style casts(函数风格强制转型)使用这样的语法:

    T(expression)                       // cast expression to be of type T

    这两种形式之间没有含义上的不同,它纯粹就是一个把括号放在哪的问题。我把这两种形式称为 old-style casts(旧风格强制转型)。

    C++ 同时提供了四种新的 cast(强制转型)形式(通常称为 new-style(新风格)或 C++-style casts(C++ 风格强制转型)):

    const_cast<T>(expression)
    dynamic_cast<T>(expression)
    reinterpret_cast<T>(expression)
    static_cast<T>(expression)

    每一种适用于特定的目的:

    • const_cast 一般用于强制消除 objects 的 constness(常量性)。它是唯一能做到这一点的 C++-style cast(C++ 风格强制转型)。
    • dynamic_cast 主要用于执行 “safe downcasting”(“安全的向下转型”),也就是说,用于确定一个 object 是否是一个 inheritance hierarchy(继承体系)中的一个特定类型。它是唯一不能用 old-style(旧风格)语法执行的 cast(强制转型)。也是唯一可能有很大运行时成本的 cast(强制转型)。(过一会儿我会提供与此相关的细节。)
    • reinterpret_cast 是特意用于底层的导致 implementation-dependent(实现依赖)(也就是说,不可移植)的结果的 casts(强制转型),例如,将一个 pointer 转型为一个 int。这样的 casts(强制转型)在底层代码以外应该极为罕见。在本书中我只用了一次,而且还仅仅是在讨论你应该如何为 raw memory(裸内存)写一个 debugging allocator(可调试分配器)的时候(参见 Item 50)。
    • static_cast 可以被用于 force implicit conversions(强制隐式转换)(例如,non-const object 到 const object(就像 Item 3 中的),intdouble,等等)。它还可以用于执行多数这样的转换的反向转换(例如,void* 指针到有类型指针,pointer-to-base(基类指针)到 pointer-to-derived(派生类指针)),虽然它不能将 const objects 转型为 non-const objects。(只有 const_cast 能做到这一点。)

    old-style casts(旧风格强制转型)依然是合法的,但是新的形式更可取。首先,在代码中它们更容易识别(对人和对像 grep 这样的工具都是如此),这样就简化了在代码中寻找 type system(类型系统)被搅乱的地方的过程。第二,更精确地指定每一个 cast(强制转型)的目的,使得编译器诊断使用错误成为可能。例如,如果你试图使用一个 const_cast 以外的 new-style cast(新风格强制转型)来消除 constness(常量性),你的代码将无法编译。

    当我想要调用一个 explicit constructor(显式构造函数)用来传递一个 object 给一个函数的时候,大概就是我仅有的使用 old-style cast(旧风格强制转型)的时候。例如:

    class Widget {
    public:
      explicit Widget(int size);
      ...
    };

    void doSomeWork(const Widget& w);

    doSomeWork(Widget(15));                    // create Widget from int
                                               // with function-style cast

    doSomeWork(static_cast<Widget>(15));       // create Widget from int
                                               // with C++-style cast

    由于某种原因,有条不紊的 object creation(对象创建)感觉上不像一个 cast(强制转型),所以在此情况下我或许会用 function-style cast(函数风格强制转型)取代 static_cast。还有,在你写出那些导致 core dump 的代码时,你通常都感觉你有很完美的理由,所以你最好忽略你的感觉并始终都使用 new-style casts(新风格强制转型)。

    很多程序员认为 casts(强制转型)除了告诉编译器将一种类型看作另一种之外什么都没做,但这是错误的。任何种类的类型转换(无论是通过 casts(强制转型)的 explicit(显式)的还是编译器添加的 implicit(隐式)的)常常导致运行时的可执行代码。例如,在这个代码片断中,

    int x, y;
    ...
    double d = static_cast<double>(x)/y;           // divide x by y, but use
                                                   // floating point division

    int x 到一个 double 的 cast(强制转型)理所当然要生成代码,因为在大多数系统架构中,一个 int 的底层表示与一个 double 的不同。这或许还不怎么令人惊讶,但是下面这个例子可能会让你稍微开一下眼:

    class Base { ... };

    class Derived: public Base { ... };

    Derived d;

    Base *pb = &d;                         // implicitly convert Derived* → Base*

    这里我们只是创建了一个指向一个 derived class object(派生类对象)的 base class pointer(基类指针),但是有时候,这两个指针的值并不相同。在这种情况下,会在运行时在 Derived* 指针上应用一个偏移量以得到正确的 Base* 指针值。

    这后一个例子表明一个单一的 object(例如,一个 Derived 类型的 object)可能会有不止一个地址(例如,它的被一个 Base* 指针指向的地址和它的被一个 Derived* 指针指向的地址)。这在 C 中就不会发生,也不会在 Java 中发生,也不会在 C# 中发生,它仅在 C++ 中发生。实际上,如果使用了 multiple inheritance(多继承),则一定会发生,但是在 single inheritance(单继承)下也会发生。与其它事情合在一起,就意味着你通常应该避免对 C++ 如何摆放东西做出假设,你当然也不应该基于这样的假设执行 casts(强制转型)。例如,将一个 object 的地址强制转型为 char* 指针,然后对其使用指针运算,这几乎总是会导致 undefined behavior(未定义行为)。

    但是请注意我说一个偏移量是“有时”被需要。objects 被摆放的方法和他们的地址的被计算的方法在不同的编译器之间有所变化。这就意味着仅仅因为你的“我知道东西是如何摆放”的 casts(强制转型)能工作在一个平台上,并不意味着它们也能在其它平台工作。这个世界被通过痛苦的道路学得这条经验的可怜的程序员所充满。

    关于 casts(强制转型)的一件有趣的事是很容易写出看起来对(在其它语言中也许是对的)实际上错的东西。例如,许多 application framework(应用程序框架)要求 derived classes(派生类)中 virtual member function(虚拟成员函数)的实现要首先调用它们的 base class(基类)的对应物。假设我们有一个 Window base class(基类)和一个 SpecialWindow derived class(派生类),它们都定义了 virtual function(虚拟函数)onResize。进一步假设 SpecialWindowonResize 被期望首先调用 WindowonResize。这就是实现这个的一种方法,它看起来正确实际并不正确:

    class Window {                                // base class
    public:
      virtual void onResize() { ... }             // base onResize impl
      ...
    };

    class SpecialWindow: public Window {          // derived class
    public:
      virtual void onResize() {                   // derived onResize impl;
        static_cast<Window>(*this).onResize();    // cast *this to Window,
                                                  // then call its onResize;
                                                  // this doesn't work!

        ...                                       // do SpecialWindow-
      }                                           // specific stuff

      ...

    };

    我突出了代码中的 cast(强制转型)。(这是一个 new-style cast(新风格强制转型),但是使用一个 old-style cast(旧风格强制转型)也于事无补。)正像你所期望的,代码将 *this 强制转型为一个 Window。因此调用 onResize 的结果就是调用 Window::onResize。你可能并不期待它没有在 current object(当前对象)上调用那个函数!作为替代,cast(强制转型)创建了一个新的,临时的 *this 的 base class part(基类部分)的 copy(拷贝),然后在这个拷贝上调用 onResize!上面的代码没有在 current object(当前对象)上调用 Window::onResize,然后再在这个 object 上执行 SpecialWindow 特有的动作——它在在 current object(当前对象)上执行 SpecialWindow 特有的动作之前,在一份 current object(当前对象)的 copy of the base class part(基类部分的拷贝)上调用了 Window::onResize。如果 Window::onResize 改变了 current object(当前对象)(可能性并不小,因为 onResize 是一个 non-const member function(成员函数)),current object(当前对象)并不会改变。作为替代,那个 object 的一份 copy(拷贝)被改变。然而,如果 SpecialWindow::onResize 改变了 current object(当前对象),current object(当前对象)将被改变,导致的境况是那些代码使 current object(当前对象)进入一种病态,没有做 base class(基类)的变更,却做了 derived class(派生类)的变更。

    解决方法就是消除 cast(强制转型),用你真正想表达的来代替它。你不需要哄骗编译器将 *this 当作一个 base class object(基类对象),你需要在 current object(当前对象)上调用 onResize 的 base class version(基类版本)。就是这样:

    class SpecialWindow: public Window {
    public:
      virtual void onResize() {
        Window::onResize();                    // call Window::onResize
        ...                                    // on *this
      }
      ...

    };

    这个例子也表明如果你发现自己要做 cast(强制转型),这就是你可能用错误的方法处理某事的一个信号。在你想用 dynamic_cast 时尤其如此。

    (本片未完,点击此处,接下篇)

    发表于 @ 2005年08月18日 01:11:00|评论(loading...)|编辑

    新一篇: [翻译] Effective C++, 3rd Edition, Item 27: 最少化 casting(强制转型)(下) | 旧一篇: [翻译] Effective C++, 3rd Edition, Item 26: 只要有可能就推迟 variable definitions(变量定义)

    评论

    #fatalerror99 (iTePub's Nirvana) 发表于2005-08-18 23:32:00  IP:
    TrackBack来自《翻译:Effective C , 3rd Edition, Item 27: 将强制转型减到最少(下)》

    Ping Back来自:blog.csdn.net
    #fatalerror99 发表于2005-08-18 18:15:00  IP: 61.186.252.*
    to Elrond
    辛苦你了,格式现在正在改,还没有全改完。比较郁闷的是15天以前发表的文章修改后要24小时才能生效。
    而且我也不知道我什么时候才能完全不再修改。仿照英文电子书倒是一个不错的主意。
    主要是交叉链接的设置以及关键字和代码的字体设置比较麻烦。
    如果有时间,我们定下一个统一的格式,然后可以一起做。
    #Elrond 发表于2005-08-18 14:21:00  IP: 61.186.252.*
    看到你在blog上的留言了,我保存的大多是过去的版本,大约在7月22日前,还有以1部分在8月上旬保存.看来都需要更新了.
    不过如果可以的话,我会全部重新制作,也看到你大多的改动了,字的颜色什么的,不过我想,如果可以的话,完全仿照英文版电子书(我下载到了)的样式来制作,如何呢?我做出一个版本就会发给你一个版本,让你确认的
    #Elrond 发表于2005-08-19 18:09:00  IP: 211.100.4.*
    不知道你对CSS了解多少,我是刚入门.我们可以定一个统一的CSS,那样格式就确定了,怎么在网上联系你比较方便?我可以把英文版的CSS发给你,同时给你我做的样书,比较简陋
    #fatalerror99 (iTePub's Nirvana) 发表于2005-08-20 07:59:00  IP: 211.100.4.*

    to Elrond
    因为最近改动比较频繁,最好先不要更新。
    我已经在我的 QQ 中加了你的号码,还给你留了言,不过这些天一直没上。
    你也可以给我发 mail,lj937@eyou.com
    #fatalerror99 发表于2005-10-10 17:02:00  IP: 211.100.21.*
    同意过客的意见,应该改为内存崩溃或保留原文较好。
    #过客 发表于2005-10-10 15:48:00  IP: 211.100.21.*
    把core dump译为核心崩溃似乎不妥
    这是早先的Unix系统中的一项功能。在半导体存储器出现前,计算机中使用王安先生发明的磁芯作为内存,磁芯的英文名称就是core,磁芯存储器就叫作core memory。如今,虽然磁芯存储器已经被淘汰,但一些人还是出于习惯把内存叫做core。当某个程序在执行时发生错误,Unix系统会把程序出错时的内存内容映像(dump)下来供程序员调试查错用。通常是写在一个叫core的文件里面。这个动作就叫做core dump。
    从上面一段文字可以看出core指代的是存储器。
    #terence zhao 发表于2008-03-03 08:50:12  IP: 61.144.54.*
    還好,看到這兒來了.其實有一些不是很明白,我是看英文版的,看不明白的就來中文版的看.不過有一點不知道:是不是在類型轉換的時候都會産生一個臨時對象?現在還沒有查找到相關說明.謝謝!
    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © fatalerror99