??xml version="1.0" encoding="utf-8" standalone="yes"?>久久精品中文无码资源站,久久国产精品77777,久久发布国产伦子伦精品http://www.shnenglu.com/theanswerzju/category/5865.htmlI有无可奈何落去?却无似曾相识归来?/description>zh-cnThu, 22 May 2008 17:26:55 GMTThu, 22 May 2008 17:26:55 GMT60C++ in Details -- Item 7: 静态绑定与动态绑?/title><link>http://www.shnenglu.com/theanswerzju/archive/2008/01/12/41009.html</link><dc:creator>TheAnswer</dc:creator><author>TheAnswer</author><pubDate>Fri, 11 Jan 2008 22:53:00 GMT</pubDate><guid>http://www.shnenglu.com/theanswerzju/archive/2008/01/12/41009.html</guid><wfw:comment>http://www.shnenglu.com/theanswerzju/comments/41009.html</wfw:comment><comments>http://www.shnenglu.com/theanswerzju/archive/2008/01/12/41009.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/theanswerzju/comments/commentRss/41009.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/theanswerzju/services/trackbacks/41009.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">   写这个Item挺偶然的Q逛cppblog时看到这文?a href="http://www.shnenglu.com/sherrylso/archive/2007/11/11/36375.html">http://www.shnenglu.com/sherrylso/archive/2007/11/11/36375.html</a>Q评论里g讨论的很Ȁ烈,感觉挺有意思的Q于是就W痒Q写下了q篇随笔?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">   在讨论静态绑定与动态绑定前Q需要先阐明两个概念Q静态类型与动态类型?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">   q两个概念只在变量是存在l承关系的类的对象的指针或者引用时才有意义Q静态类型是你声明的cdQ编译时卛_知;而动态类型是指这个指针或者引用实际指向的对象的类型,q行时才可知。D几个例子Q?br>假设D是从B公有l承?br>   B *bp1; // 静态类?B* 动态类型无<br>   B *bp2 = new B; // 静态类?B* 动态类?B*<br>   B *bp3 = new D; // 静态类?B* 动态类?D*</p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">   静态绑定的含义为函数的行ؓ取决于对象的静态类型,而动态绑定的含义为函数的行ؓ取决于对象的动态类型,有以下原则:<br>   1. 非虚函数静态绑定?br>   2. 虚函数动态绑定?br>   3. 函数的缺省参数静态绑定?br>   4. 子类中仅需函数名即可覆盖父cȝ多个重蝲函数?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">   Scott Meyers在《Effctive C++?nd Edition中Item 37~38x阐述q个问题的,大家可以参考一下,下面通过一D小E序做个说明?br><br></p> <div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">#include <iostream><br><br>using namespace std;<br><br>class B<br>{<br>public:<br>    virtual void func()<br>    {<br>        cout << "B::func()\n";<br>    }<br><br>    void func(double d)<br>    {<br>        cout << "B::func(" << d << ")\n";<br>    }<br>};<br><br>class D : public B<br>{<br>public:<br>    void func()<br>    {<br>        cout << "D::func()\n";<br>    }<br><br>};<br><br>int main()<br>{<br>    B b;<br>    D d;<br>    B& rb = d;<br><br>    d.func();<br>    //d.func(2.3);<br><br>    rb.func();<br>    rb.func(2.3);<br><br>    return 0;<br>}<br></div> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><br>   在VC9下的q行l果?br>   D::func()<br>   D::func()<br>   B::func(2.3)<br>   如果Ld.func(2.3);的注释,则编译即出错?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">   Z么会有这Ll果呢?l合上面?条原则来看,B中有两个版本的重载func函数Q一个ؓ虚函敎ͼ一个ؓ非虚函数QD中重定义了承而来的func()Q但是根据原?Q原本也可以l承而来的func(double)也被D自己定义的func()l覆盖了Q换a之,现在D中只有一个func()函数。由于d的静态和动态类型均为DQ运行d.func(2.3)的时候发现根本找不到定义Q只能编译报错。现在来看rbQ由前所qͼrb的静态类型ؓBQ动态类型ؓDQ于是rb.func()Ҏ动态绑定表CؓD::func()的行为,rb.func(2.3)Ҏ静态绑定表CؓB::func(double)的行为?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">   我们可以来猜想以下ؓ什么会有这L代码Q设计者原意可能是想仅重定义func()而承func(double)的默认行为,可惜׃C++中覆盖规则,事与愿违。所以当L虚函C重蝲q两U不同时期决定的多态时Q一定要心。从OO设计的角度来_虚函数几乎肯定是要被l承c重写的Q而非虚函数是l不应该被重定义的,所以当你的设计中出现重载函C是同函数或者非虚函数时Q就要小心覆盖问题了?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">   关于函数~省参数问题Q《Effective C++?nd Editon Item 38讲得很清楚,q里׃赘述了?img src="http://www.shnenglu.com/CuteSoft_Client/CuteEditor/images/emsmile.gif" align=absMiddle border=0><br></p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"> </p> <img src ="http://www.shnenglu.com/theanswerzju/aggbug/41009.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/theanswerzju/" target="_blank">TheAnswer</a> 2008-01-12 06:53 <a href="http://www.shnenglu.com/theanswerzju/archive/2008/01/12/41009.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ in Details -- Item 3 : 引用与函?/title><link>http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39509.html</link><dc:creator>TheAnswer</dc:creator><author>TheAnswer</author><pubDate>Mon, 24 Dec 2007 07:34:00 GMT</pubDate><guid>http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39509.html</guid><wfw:comment>http://www.shnenglu.com/theanswerzju/comments/39509.html</wfw:comment><comments>http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39509.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/theanswerzju/comments/commentRss/39509.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/theanswerzju/services/trackbacks/39509.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">    即仅仅把C++看作"A Better C"Q引用也是一个极其有价值的Ҏ,在函数的参数表和q回D两个领域Q引用给了我们一个比传值更高效Q比传指针更直观的新的选择?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">    引用是什么?q个问题其实q不Ҏ回答Q很多h会说引用是一个别名,q个理解g太过模糊。用Eckel的说法,引用像是能自动被编译器间接引用的常量型的指针。你无需考虑它是否被初始化,也不用考虑怎样对其解引用,因ؓ~译器会监督你做好前者,又会自动的帮你完成后者。一个引用L和一块合法的存储单元相联p,q就是你唯一需要时ȝ记的?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">    先说函数参数吧。当你仅仅需要参数的值来做函C的运时Q传递一个常量引用一般来说会好于g递。首先是效率Qg递就意味着拯构造函数的调用Q自然也有析构函数的开销Q而这些都可以在传递引用的时候得以避免的Q从函数调用者来看,使用传递引用的函数和传g递的函数的调用Ş式ƈ没有区别Q对于承体p而言Q用引用传递还可以避免切割或者分片问题,因ؓ引用可以很好的实现向上类型{换。当Ӟ如果只是需要用|你应该将引用声明为const。当需要改变外部对象的时候,引用的对手就变成了指针,两者在效率上可以视为同{,引用在函数的~写者的角度来看更自Ӟ却容易让函数的调用者生؜淆,因ؓq种变换性被隐藏了。很难说谁好谁坏Q就看具体情늚权衡吧?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">    从效率的角度来说Q返回值当然也应该选择引用Q不q当你返回局部对象的引用Q或者函数内部用new初始化的指针的引用时Q情况就变得很糟p了。前者在函数调用者用它的时候已l被销毁了Q也是你违背了引用L和一块合法的存储单元相联pȝ准则Q后者似乎解决了q个引用有效性的问题Q不q很遗憾Q引发了一个更大的问题Q内存泄Ԍ因ؓ没有一个合适的机制M证在正确的时间deleteq个指针Q每一ơ的函数调用都导致一点内存泄Ԍq是非常可怕的。其实原则也很简单,当你实需要一个新的对象的时候,你就应该为其付出构造和析构的开销Q最典型是operator +, -, *, /函数。当然好心的~译器还是有可能帮你做返回g化的Q把函数q回的对象直接构造在你赋值的对象的内存上Q一切又变得好了?img src="http://www.shnenglu.com/CuteSoft_Client/CuteEditor/images/emsmile.gif" align=absMiddle border=0></p> <br> <img src ="http://www.shnenglu.com/theanswerzju/aggbug/39509.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/theanswerzju/" target="_blank">TheAnswer</a> 2007-12-24 15:34 <a href="http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39509.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ in Details -- Item 6 : c设计者的核查?/title><link>http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39462.html</link><dc:creator>TheAnswer</dc:creator><author>TheAnswer</author><pubDate>Sun, 23 Dec 2007 18:54:00 GMT</pubDate><guid>http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39462.html</guid><wfw:comment>http://www.shnenglu.com/theanswerzju/comments/39462.html</wfw:comment><comments>http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39462.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/theanswerzju/comments/commentRss/39462.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/theanswerzju/services/trackbacks/39462.html</trackback:ping><description><![CDATA[<span style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">    ym一把Adrew KoenigQ《C++沉思录》绝对可以算C++领域l典著作。以下条ƾ摘自其中第4章,下面对Meyers的引用是我自己加上的Q那边讲得更l,MeyersL会不厌其烦的解释他的每一个条ƾ?br> <br>    以下问题都没有确切的{案Q关键是要提醒你思考牠们,q确认所做的事情是出于有意识的决定,而不是偶然事件?br> <br>    1.你的c需要一个构造函数吗Q?br>        复杂的类需要构造函数来隐藏牠们内部的工作方式?br> <br>    2.你的数据成员是私有的吗?<br>        Meyers98 Item20<br> <br>    3.你的c需要一个无参的构造函数吗Q?br>        Meyers96 Item4<br> <br>    4.是不是每个构造函数初始化所有的数据成员?br>        Meyers98 Item12<br> <br>    5.c需要析构函数吗Q?br>        该类是否分配了资源,而这些资源又不会由成员函数自动释放?br> <br>    6.c需要一个虚析构函数吗?<br>        是否会通过基类指针d除派生类对象?br>        Meyers98 Item14<br> <br>    7.你的c需要复制构造函数吗Q?br>        复制该类的对象是否就相当于复制其数据成员和基cd象?br>        Meyers98 Item11<br> <br>    8.你的c需要一个赋值操作符吗?<br>        如果需要复制构造函敎ͼ多半也会需要一个赋值操作符?br> <br>    9.你的赋值操作符能正的对象赋l对象本w吗Q?br>        Meyers98 Item17<br> <br>    10.你的c需要定义关pL作符吗?<br>        逻辑上是否支持相{操作,cȝ值是否存在某U排序关pR?br> <br>    11.删除数组时你C了用delete[]了吗Q?br> <br>    12.记得在复制构造函数和赋值操作符的参数类型中加上const了吗Q?br>        复制对象不会改变原对象?br> <br>    13.如果函数有引用参敎ͼ牠们应该是const引用吗?<br>        只有当函数想改变参数Ӟ才应该有不用const声明的引用参数?br> <br>    14.记得适当地声明成员函Cؓconst的了吗?<br>        如果信一个成员函C用修改牠的对象,可以声明牠为constQ这样就可以把牠用于const对象了?br> <br>    ? Meyers96: Scott Meyers More Effective C++.               <br>    ? Meyers98: Scott Meyers Effective C++ 2nd edition.<img src="http://www.shnenglu.com/CuteSoft_Client/CuteEditor/images/emsmile.gif" align=absMiddle border=0><br><br></span> <img src ="http://www.shnenglu.com/theanswerzju/aggbug/39462.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/theanswerzju/" target="_blank">TheAnswer</a> 2007-12-24 02:54 <a href="http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39462.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ in Details -- Item 5 : 内联真的那么好?/title><link>http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39461.html</link><dc:creator>TheAnswer</dc:creator><author>TheAnswer</author><pubDate>Sun, 23 Dec 2007 18:52:00 GMT</pubDate><guid>http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39461.html</guid><wfw:comment>http://www.shnenglu.com/theanswerzju/comments/39461.html</wfw:comment><comments>http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39461.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/theanswerzju/comments/commentRss/39461.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/theanswerzju/services/trackbacks/39461.html</trackback:ping><description><![CDATA[<span style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">    几乎每个C/C++E序员,都会把效率视为程序的生命U,以至于有时甚至不愿意承担函数调用的开销。是的,单的一句函数调用,却意味着参数压栈Q生成汇~语a的CALLQ返回参敎ͼ执行汇编语言的RETURNq么多的额外开销Q这一切可能是仅仅Z使用某个只有一行代码的函数体,更何况call指o常常会导致指令缓冲区被清I,引v局部性的丧失。这对视效率为生命的E序员来_该是多么可怕的事情啊?br> <br>    于是一些C/C++E序员发C预处理器q个好东西,用宏来模拟一个函数调用,消除了所有开销Q又g得到了和函数调用同样的效果。可惜好景不长,׃仅仅是简单的文本替换Q会出现表达式在宏内展开时优先背离期望Q于是}慎的E序员们只能把参数都用括hhQ可是即使是q样Q当面对参数求值的副作用时Q还是显的无能ؓ力。对于钟情于OO的C++E序员,他们发现了一个更p糕的问题:用宏模拟的函数无法访问类的私有成员,以致于无法其成为成员函数?br> <br>    q好C++q提供了另一个利器:内联。只要在函数定义前简单的加上inline关键字,可以用普通函数实现宏的效率,外加可预计的行ؓ和类型安全,而且~译器还可以对函C执行特定环境下的优化。你可以把定义放在头文g中,用于每个使用q个函数的文件而不会生多个定义的错误。至于成员函敎ͼ更妙了,只要你在cȝ内部定义Q就自动成ؓ内联函数Q甚至不需要额外声明,q种用法被大量的用ؓcL员的讉K函数?br> <br>    可是。。。你也许会问Q内联真的那么美好吗Q那Z么C++不默认所有函数都是内联函敎ͼq样不是更省事吗Q?br> <br>    q是那句老话Q天下没有免费的午餐Q在你n受内联给你带来的好处的同Ӟ你也在ؓ此付ZP有些很明显,有些你却未必意识到?br> <br>    最显而易见的Q由于用函数体代替函数调用,目标代码的体U几乎不可避免的增大了,q意味着更多的内存占用。虚拟内存?是的Q虚拟内存可以容Ux大的E序Q但是过于庞大的代码体积很有可能D频繁的页面调度甚至系l颠,一个在I/O上频J操作的E序Q你能指望牠快到哪里dQ?br> <br>    和static或者const不一Pinline仅仅意味对编译器一个徏议或者邀P例如面对递归函数的时候,l大多数~译器会无视你愚蠢的。被~译器拒l的时候,会发生什么呢Q现行C++标准规定q个情况下编译器p像对待非内联函数一P当你把定义放在头文g而用于多重编译单元的时候,多定义错误便是不可避免的。所以,请不要低估编译器的智慧,愚蠢的内联徏议最后买单的q是你自己?br> <br>    那编译器到底用什么准则来军_是否搭理你的inline呢?标准的答案是没有{案Q但是有一些基本的原则可以作ؓ参考。首先,函数太复杂的时候,~译器一般会攑ּ内联Q例如上面提到的递归调用Q函数内有@环,再或者函Cp多语句组成,M一旦编译器觉得不划的时候牠很理智的选择攑ּQ当昑ּ或者隐式地取函数地址q且使用地址的,必然不会发生内联Q你M能指望编译器Z生成一个ƈ不存在的函数的地址吧;构造函数和析构函数一般也不适合内联Q因两个家伙l常会比你看到的函数体更为复杂,其是涉及承时的层ơ徏立与销毁的时候。还有一点也许出乎你的意料,内联是和函数调用而非函数本n联系在一LQ也是说编译器完全可能在某些调用点使用内联而在其他调用点不予内联,q完全根据编译器对上下文的判断而定?br> <br>    没有保证E序没有bugQ所以才需要调试。可是,当调试器遇到内联函数的时候,你能惛_一个好办法让其不晕菜吗Q怎么在一个不存在的函数里讄断点呢?怎么单步执行到这样一个函数呢Q怎么俘获对它的调用呢Q求求你了,同情一下可怜的调试器吧?br> <br>    其实只要认识C点,内联的本质是一U优化,事情变得简单了。优化是建立在程序本w的正确性的基础上的Q而且一般而言Q有那些通晓生成代码和执行环境的工具来执行往往比程序员效果更好?img src="http://www.shnenglu.com/CuteSoft_Client/CuteEditor/images/emsmile.gif" align=absMiddle border=0><br><br></span> <img src ="http://www.shnenglu.com/theanswerzju/aggbug/39461.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/theanswerzju/" target="_blank">TheAnswer</a> 2007-12-24 02:52 <a href="http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39461.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ in Details -- Item 4 : ~译器的q后行ؓhttp://www.shnenglu.com/theanswerzju/archive/2007/12/24/39460.htmlTheAnswerTheAnswerSun, 23 Dec 2007 18:51:00 GMThttp://www.shnenglu.com/theanswerzju/archive/2007/12/24/39460.htmlhttp://www.shnenglu.com/theanswerzju/comments/39460.htmlhttp://www.shnenglu.com/theanswerzju/archive/2007/12/24/39460.html#Feedback0http://www.shnenglu.com/theanswerzju/comments/commentRss/39460.htmlhttp://www.shnenglu.com/theanswerzju/services/trackbacks/39460.html    和C语言相比QC++的编译器除了做更严格的类型检查的工作外,g也变得更为勤快了Q会在幕后默默帮你补全你看v来漏掉的函数。一个不了解~译器幕后行为的C++E序员简直和一个不知道自己汽RҎ的司机一样可怕。本文就是ؓ了消除这U可怕而写?br> 
    假设你定义了一个空c?br>    class A {};
    在C++~译器通过它的时候,q个单的I类也变得丰富多彩了Q事实上你多了一个缺省构造函敎ͼ一个拷贝构造函敎ͼ一个赋D符Q一个析构函C及一对取地址q算W,怎么P默默Z声明了这么多函数QC++~译器够勤快的了吧。不q天下没有免费的午餐QQ劳Q怨的~译器可能在不经意间已经l你设下了陷q?br> 
    1.~省构造函数。实际上Q它什么都不做Q很安全Q而且当你声明了至一个构造函数的时候,~译器就不再生成~省构造函数?br> 
    2.拯构造函敎ͼ赋D符Q。缺省拷贝构造函敎ͼ赋D符Q对cȝ非静态数据成员进?"以成员ؓ单位? 逐一拯构造(赋|。也是说会对类中的非静态数据成员进行递归的拷贝构造函敎ͼ赋D符Q调用,直到扑ֈ一个拷贝构造函敎ͼ赋D符Q或者内|类型ؓ止。对于内|类型,则用从源对象到目的对象的逐位拯。可是。。。当你的数据成员是指针的时候呢Q结果是源对象和目的对象的指针成员都指向了同一片内存空_如果目的对象原来有指向的内容,׃生了内存泄露Q即使没有,只要有一个对象先消亡Q另一个的指针悬IZQ只是多么可怕的事情啊。所以,当类中有指针成员的时候,应该自己定义拷贝构造函敎ͼ赋D符Q,至于是简单拷贝还是引用计敎ͼ可以根据实际情况而定了?br> 
    3.析构函数。缺省析构函C不做什么特别的事情Q仅仅是销毁对象。不q有炚w要注意,生成的析构函C般是非虚拟的Q除非是从一个声明了虚拟析构函数的基cȝ承而来。析构函敎ͼ虚拟析构函数Q纯虚析构函敎ͼq三者有什么区别呢Q首先,析构函数和构造函CP是可以沿cdơ进行调用的Q也是说析构函C从你要删除的cd始,一直向上到基类为止Q以实现cdơ的拆卸Q但是当你希望通过基类的指针去删除zcȝ对象的时候,如果没有虚拟析构函数Q那么行为就是ؓ定义的,所以当你的cM有大于等于一个虚函数的时候,你就应该立刻意识刎ͼ你需要一个虚拟析构函敎ͼ或者说Q你应该保证基类拥有一个虚构造函数。那U虚析构函数又有什么用呢?U虚函数生抽象类。有些时候,你想使一个类成ؓ抽象c,但刚好又没有MU虚函数。怎么办?因ؓ抽象cL准备被用做基cȝQ基cd要有一个虚析构函数Q纯虚函C产生抽象c,所以方法很单:在想要成为抽象类的类里声明一个纯虚析构函敎ͼ是的Q就是这么简单。当然啦Q你q需要ؓq个U虚析构函数提供一个定义,哪怕仅仅是{}Q而在其派生类中,~译器会自动生成一个析构函数的定义?br> 
    4.取地址q算W。这个比较简单,只是单纯的返回了对象的地址Q不q根据返回值是否ؓconstq是出现了重载?br> 
    q里q应该考虑一U情况,有时候你可以定不需要某些隐式生成的函数。例如在你的cM拯和赋值都是不允许的,q时候你p坚决的禁止编译器生成它们。方法其实很单,把它们声明ؓprivateQƈ且不要去定义。是的,p么简单,但你试图调用的时候,~译器会哇哇大叫Q你又避免了一ơ错误?img src="http://www.shnenglu.com/CuteSoft_Client/CuteEditor/images/emsmile.gif" align=absMiddle border=0>



TheAnswer 2007-12-24 02:51 发表评论
]]>
C++ in Details -- Item 2 : cd转换http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39459.htmlTheAnswerTheAnswerSun, 23 Dec 2007 18:46:00 GMThttp://www.shnenglu.com/theanswerzju/archive/2007/12/24/39459.htmlhttp://www.shnenglu.com/theanswerzju/comments/39459.htmlhttp://www.shnenglu.com/theanswerzju/archive/2007/12/24/39459.html#Feedback0http://www.shnenglu.com/theanswerzju/comments/commentRss/39459.htmlhttp://www.shnenglu.com/theanswerzju/services/trackbacks/39459.html    L会有一些东西,我们不喜Ƣ却w不开Q比如说考试Q又比如说C++中的cd转换。作ZU强cd的编E语aQ类型{换就像现实生zM变换国籍一h怖,不过也没办法Q程序员要改变变量的属性,不是~译器能L的,像张铁林徐帆之挂着外国c的华h演员Q我们除了在心里歧视几次之外也没啥实质性的理由去谴责。C++世界和现实一PL有很多让我们感到无奈的地斏V?br> 
    cd转换不外乎两U:昑ּcd转换和隐式类型{换,下面分别说明?br> 
    1.昑ּcd转换。C++引入了四个新的类型{换符Q可以替代C风格cd转换的全部功能,q提供了更强大的功能和更好的安全性,克服了C风格的类型{换目的性不明确和难以查扄~陷?br> 
    (1).static_castQ用于明定义的变换Q基本上和通用的C风格cd转换有着同样的能力,含义以及功能限制。包括编译器允许我们所做的不用强制转换?#8220;安全”变换和不太安全但清楚定义的变换?br> 
    (2).const_castQ用来改变对象的const或者volatile属性,而且q译器强制U束语意只能做这个变换。这个{换符其实很鸡肋,因ؓ把一个非帔R指针或引用赋l一个常量指针或引用本n是合法的;反过来的话一般来说用cd转换L对象的常量属性通常是不好的~程风格Q因为完全有可能~译器已l把该对象存储在了只d存中Q而且逻辑上来说很难找到去除const属性的合理解释Q如果只是和cL员相关的Q则应该使用mutable?br> 
    (3).dynamic_castQ用以针对一个承体pd向下或者横行的安全转换Qƈ且可以知道{换是否成功,p|会通过I指针或者异常(因ؓ没有I引用)来提醒程序员。值得注意的是q个l承体系里必要有虚函数Q因为dynamic_cast需要读取VTABLE内的信息来做判断Q这里也可以引出RTTI的问题,以后再写吧。这个{换符挺实用的Q也没有什么致命缺P是需要一炚w外的开销吧?br> 
    (4).reinterpret_castQ重解释转换Q搞不太清楚Q暂时也没有发现讲的比较透彻的资料。引用Eckel的话“使用reinterpret_cast通常是一U不明智Q不方便的编E方?#8221;Q不用就不会出错了?br> 
    2.隐式cd转换。C++的编译器和C相比Q勤劳了太多太多QL喜欢默默为我们做什么事情,太多时候这l我们带来了便利Q但q犹不及QQ劳Q怨的~译器也会给我们带来陯Q比如说隐式cd转换?br> 
    在C和C++中,如果~译器看C个表辑ּ或者函数调用用了一个不合适的cdQ它׃试着执行一个自动类型{换,从现在的cd转换到所要求的类型。如果只是固有类型,一切似乎很完美Q因为可以把一个intg送给定义为double参数的函敎ͼ不过一旦涉及到了自定义cdQ事情就变糟p了?br> 
    有两U函数可能会D隐式cd转换Q单参数构造函敎ͼ也可以是除了W一个参数其他都有默认值的多参数构造函敎ͼ以及cd转换q算W重载函数。前者由目的cL行{换,也就是增加一个新cȝ时候ؓ现有pȝ增加了新的{换途径Q后者由源类执行转换Q所以只有后者才能实C自定义类型到内置cd的{换?br> 
    但是隐式转换通常都是不安全的。经怼在你Ҏ不希望进行类型{换的时候被调用Q从而可能导致错误的代码利通过~译或者程序的q行不符合预期,另一斚wQ可能会和重载解析生冲H,q在提供了不止一U类型的自动转换而且恰好函数又被重蝲的时候就发生了,不过q种情况~译器会抗议Q其实好于前一U情c?br> 
    解决Ҏ其实q不复杂Q想办法自己控制cd转换是了,像《C专家~程》里提到的一个重要原则:“知道自己在做什么!”所以就可以使用名字不同于语法关键字但功能相同的函数来替代{换运符。有个经典的例子是stringcM有的是必被昑ּ调用的c_str()成员函数而非隐式cd转换。对于单参数构造函敎ͼ只要在函数声明前加上explicit关键字,pN免了隐式cd转换Q而保持了昑ּcd转换的合法性?img src="http://www.shnenglu.com/CuteSoft_Client/CuteEditor/images/emsmile.gif" align=absMiddle border=0>



TheAnswer 2007-12-24 02:46 发表评论
]]>
C++ in Details -- Item 1 : const的正用?/title><link>http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39458.html</link><dc:creator>TheAnswer</dc:creator><author>TheAnswer</author><pubDate>Sun, 23 Dec 2007 18:42:00 GMT</pubDate><guid>http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39458.html</guid><wfw:comment>http://www.shnenglu.com/theanswerzju/comments/39458.html</wfw:comment><comments>http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39458.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/theanswerzju/comments/commentRss/39458.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/theanswerzju/services/trackbacks/39458.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">    是前言Q回头看看,q一q多来读的C++书也不算了Q但是昨天还是被Herb Sutter的《Exceptional C++》给狠狠打击了,几乎每次都踩q这位标准委员会d的陷q之中,既有惭愧Q又有I补不的ƣ喜和恍然大悟的快乐。反思一下,其实不少东西自己以前也在各种资料中看到过Q但没有ȝQ整个C++知识体系松散而布满漏z,所以就有了把技术上的ȝ记录下来的念_一斚w帮自q清思\Q另一斚w也可以我的space看v来文化层ơ高一些,无病d一些。似乎有个说法叫“l节军_成就”Q于是我取了个“C++ in Details”的名字,写的都是C++中的技术细节,虽然l微但肯定研I阶技术的基石。内容和观点都是援引自读q的Bruce Eckel, Scott Meyers, Herb Sutter{大师的著作Q只是做个整理,大师们应该不会和我这个小菜鸟计较版权吧?br> <br>    a归正传,׃const的正用法开始吧?)</p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"> <br>    ȝ来说Qconst有以下几U用场合,值替代,指针Q函数参数和q回|cM的constQ这几者概念上是一致的Q但是用法却存在着l微的差别,也是本文需要说明的问题?br> <br>    1.值替代。用以取?define实现值替代的全部功能Q作ZU更优的用法Qconstq可以提供类型安全以及调试时的便利,~译器也可以q行帔R折叠优化。编译器通常q不为const分配存储I间Q但出现取const的地址{操作时必需q行存储I间分配Q这U不能完全避免导致了const的定义默认ؓ内部q接。值得注意的是当const用于数组和结构体{集合时只意味着一块不能改变的存储区域Qƈ不能在编译期间用它的倹{?br> <br>    2.指针。可以以“*”为分界线Qconst出现在左侧时修饰指针指向的对象,右侧时修饰指针本w的|也就是指针里存储的地址。可以把一个非const对象的地址赋给一个const指针Q但是不能把一个const对象的地址赋给一个非const指针Q不q存在一点小的例外Q就是例如char *str = "TheAnswer"却是合法的,不过q是应该避免q种用法Q用const char *str = "TheAnswer"或者char str[] = "TheAnswer"其中一个替代更好一些?br> <br>    3.函数参数。函数参C的const意味着变量的初g会被函数所修改Q这是一个函C者而非函数的调用者的工具。所以当g递的时候,参数列表中的const完全是冗余的Q如果一定需要,则可以通过在函C内定义一个指向常量参数类型的引用q初始化为参数来U束自己。当传递地址的时候,首先选择的应该是传递引用,而且是const引用。有以下几个好处Q在调用者看来,效果完全{同传g递,但是在传递大对象的时候,避免了构造函数的开销Q效率上有优势;另外const引用可以接受一个时对象作为参敎ͼq也是指针和非const引用所无法做到的(指针需要接受一个显式的地址Q而时对象是帔RQ不能把一个常量赋l一个非帔R引用Q?br> <br>    4.函数q回倹{这里需要区分的东西更多一些。即使是按D回,也需要区分内|类型和自定义类型,前者是否加const无所谓,因ؓ~译器帮忙把q个q回g让其成ؓ叛_|对于后者,const非帔R要了Q因Z般来_修改一个通过D回的函数q回值L一件荒谬的事情。返回地址时修改函数的q回值是h合理性的Q所以需要通过const来区分,如果q回值加上了constQ那么把q回值当左g用时p被编译器有效的阻止?br> <br>    5.cM的const。这里还需要两点来看<br>    (1).cȝconst数据成员。非static的const数据成员仅仅意味着在对象生命期内,q是一个常量,但是每个对象可以包含一个不同的|所以只能在构造函C对其q行初始化,一般放在初始化列表之中。当你想要一个编译期间的帔RӞ则需要用static constQƈ在定义的地方便对其初始化Q这可以用来取代以前?#8220;enum hack”的小把戏?br>    (2).const对象和成员函数。如果声明一个成员函CؓconstQ则该函数可以ؓ一个const对象所调用Q值得注意的是在定义函数的时候要重申const说明。由于const成员函数可以同时为const和非const对象所使用Q所以应该把不修Ҏ据成员的M函数都声明ؓconst?br> <br>    const可以牉|Z连带问题,q是下面的主要内宏V?br> <br>    1.C中的const。就像马克思说?#8220;物质军_意识Q意识反作用于物?#8221;QC++中的不少概念也渗透回了C语言Qconst是其中一个。但是const在C中的含义仅仅Z个不能被改变的普通变量,甚至不能被看作编译期帔RQƈ且在C中const被默认ؓ是外部连接,L会分配一块存储区域。所以C中的const用处比C++得多了?br> <br>    2.临时对象。如果一个对象被创徏Q而又不是在堆上被创徏的,而且q没有名字,那么q个对象是临时对象。一般在Z函数调用能够成功而进行隐式类型{换和函数q回对象时的隐式cd转换时生时对象。前者只有在传g递或者把对象传递给声明为const引用的参数时才会发生?br> <br>    3.mutable和volatile。这是两个和const有密切关pȝ关键字。在cȝ声明里用mutableQ可以指定一个特定的数据成员可以在一个const对象里被改变Q而且把这U常量性的~Z公开CcL口之中,当然q里面还涉及到按位const和按逻辑const的概念差别。volatile则告诉编译器不要擅自对该数据q行优化Q因为可能存在不可知的环境改变此变量的可能?img src="http://www.shnenglu.com/CuteSoft_Client/CuteEditor/images/emsmile.gif" align=absMiddle border=0></p> <br> <img src ="http://www.shnenglu.com/theanswerzju/aggbug/39458.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/theanswerzju/" target="_blank">TheAnswer</a> 2007-12-24 02:42 <a href="http://www.shnenglu.com/theanswerzju/archive/2007/12/24/39458.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.ccgangjiegou.cn" target="_blank">ƷŮ߳׾þþ</a>| <a href="http://www.mztkn.cn" target="_blank">þ</a>| <a href="http://www.eoga.cn" target="_blank">þˬˬƬAV鷳</a>| <a href="http://www.zkduo.cn" target="_blank">þ99žŹѿС˵</a>| <a href="http://www.ktrb.net.cn" target="_blank">޾ƷþþþþðĦ </a>| <a href="http://www.ajchugui.cn" target="_blank">þɫۺҹž</a>| <a href="http://www.kunow.cn" target="_blank">ҹƷþþþþþ</a>| <a href="http://www.cshlyfm.cn" target="_blank">99þþƷþþþþ崿</a>| <a href="http://www.dgjiajun.net.cn" target="_blank">ӰɫۺϾþ</a>| <a href="http://www.squc.cn" target="_blank">˸ŮѲžþþ</a>| <a href="http://www.ab1987.cn" target="_blank">þþþƷƵѹۿ</a>| <a href="http://www.huangshanlife.cn" target="_blank">ҹþƷþþþ</a>| <a href="http://www.qdaigo.com.cn" target="_blank">þ93Ʒ91þۺ </a>| <a href="http://www.sbznw.cn" target="_blank">ݹ˾þ91</a>| <a href="http://www.sky1314.cn" target="_blank">ɫþþþSWAGƷ</a>| <a href="http://www.xwbu.cn" target="_blank">þ㽶һëƬ</a>| <a href="http://www.qnzj.org.cn" target="_blank">˾þô߽AVۺӰԺ</a>| <a href="http://www.xx5a4.cn" target="_blank">þݹֻƬ</a>| <a href="http://www.gaguni.cn" target="_blank">þֻоƷ߹ۿ</a>| <a href="http://www.jupucha.com.cn" target="_blank">þֻоƷþ</a>| <a href="http://www.huizegufen.cn" target="_blank">þþƷAVɫ</a>| <a href="http://www.ruozhu.com.cn" target="_blank">þþƷŷƬ</a>| <a href="http://www.gvyf.cn" target="_blank">Ʒtvþþþþþ</a>| <a href="http://www.shuo123.cn" target="_blank">þþŷղa</a>| <a href="http://www.1yaofang.cn" target="_blank">þ޵Ӱ</a>| <a href="http://www.gzzmlhlaw.cn" target="_blank">þˬ˸߳AV</a>| <a href="http://www.odcb.cn" target="_blank">97þþþ</a>| <a href="http://www.songyuan163.net.cn" target="_blank">ɫۺϾþ</a>| <a href="http://www.zhangjiaying.cn" target="_blank">þҹ³˿ƬҹƷ</a>| <a href="http://www.yzx777.cn" target="_blank">ɫۺϾþۺ</a>| <a href="http://www.meelin.cn" target="_blank">ҹþþþƷӰԺ</a>| <a href="http://www.gsm1.com.cn" target="_blank">99鶹þþùƷ</a>| <a href="http://www.ekqt.cn" target="_blank">þ޹˾Ʒɫ</a>| <a href="http://www.shqidao.cn" target="_blank">Ļþҹ</a>| <a href="http://www.yousms.cn" target="_blank">ۺ˾þۺ</a>| <a href="http://www.vip910.cn" target="_blank">þùɫavѿ</a>| <a href="http://www.geigi.cn" target="_blank">ۺ˾þۺ</a>| <a href="http://www.ijlm.cn" target="_blank">ŷ޳ҹƷþ </a>| <a href="http://www.usgold.cn" target="_blank">þþƷav鶹С˵</a>| <a href="http://www.abctoy.com.cn" target="_blank">ձWVһһþ㽶</a>| <a href="http://www.fanglan-tech.cn" target="_blank">ĻƷþ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>