新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 计算机科学论坛计算机技术与应用『 C/C++编程思想 』 → C++语言常见问题解 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 8594 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: C++语言常见问题解 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客楼主
    发贴心情 C++语言常见问题解

    这是从台湾的http://www.cis.nctu.edu.tw/chinese/doc/research/c++/C++FAQ-Chinese/发现的《C++ Frequently Asked Questions》的繁体翻译,作者是:叶秉哲,也是《C++ Programming Language》3/e繁体版的译者,该文章是非常的好,出于学习用途而将它转贴,本人未取得作者的授权,原文章的版权仍然归属原作者.


    C++语言常见问题解

    C++语言常见问题解答

    译后感言

    叶秉哲 83.11.26.

    翻译这份 USENET comp.lang.c++ FAQ 也算是始料未及的事。一开始是

    研发组穆信成同学有个构想:将一些好的英文文件翻译出来,以造福苍生﹑

    解民倒悬……。这点子很好,当下就赞同这提议。不过没想到,「赞同」该

    方案似乎还不够,我看到了一抹神秘的微笑自他嘴角浮起……结局就是一时

    不察,祸从口出啦!

    前面所提的其实只是近因。事实上,我对「翻译」一事虽无作品,关怀

    之忱却袅绕甚久。认识我的朋友应该知道:我对中译书籍品质之批评向来是

    不假辞色的,不限于计算机类。两年来「PC Magazine 中文版」的无责任书评

    专栏,侯 SIR对这课题亦时有针砭之言。这些都促使我对翻译一事比以往更

    留上了神。

    真正的导火线,应该是源自我的一篇书评(将刊于 83 年 12 月「PC

    Magazine中文版」),里面也有满辛辣的讽刺批评,只差没有点名批斗而已

    (不过有心人应该看得出我点名的对象)。为了避免予人「只会批评,不会

    做事」之讥,也为了积贮多年翻译理论之余,有个落实的机会,便挑选了这

    份文件。

    对这份 FAQ:技术上我有掌握的能力,它的文字我有吸收的能力,对这

    主题我也有热诚,所以才会选它为我的中长篇翻译处女作。

    这真的是「中长篇」!该原文约有 150,000 bytes,(对原作者的费力

    及慷慨,在此表示敬意!)中译后约 123,000 bytes,(由此可见中文之精

    简﹑扼要﹑表现力强,若以文言文为之……哇!不敢想象!)不要说我翻得

    累,各位光是看着就很累!断断续续花了近七个礼拜的时间才把它完成,底

    下就把这过程的酸甜苦辣提供出来,聊作感言﹑后跋吧!

    中文翻译向有信﹑达﹑雅之最高准则。对纯文学而言,信达雅三者都必

    须兼顾(我将「雅」的意思扩大解释了),才能让读者无视语言的隔阂,而

    能尽情领略原作的思想与风采。我所能见到最好的例子,就是罗珞珈译﹑志

    文出版的《老人与海》一书,吾尝中英并列以观,醍醐灌顶之乐也。对哲学

    类而言,微言大义,字字珠玑,「信」无疑是终极(或更严苛地说:唯一)

    圭臬,任何取舍抉择都该以它为准。不过不要小看了它,一字之差,谬之千

    里,对该主题没有绝对把握的话,会替地球多制造一份垃圾。在哲学这领域

    ,牟宗三先生译的康德三批判,实属翘楚。至于我们这种科技类,老实说,

    大多数不怎么挑的读者但求「信」而已,甚至不必「太信」,只要「有」,

    就勉强接受。侯捷就曾说:「我们的读者是最逆来顺受的一群……再挑就没

    得看了!」是的,再挑,就只能死啃原文书看了。这无疑是科技族群的悲哀。

    翻译科技文章,我的看法是:首要条件乃将原作的技术完整传达出来。

    技术类不像通俗文学,很难由上下文来推敲某关键处真正含意,所以「信」

    字该区首位。译者不应以自我的主见投射于译作上(不论它客观上看来是否

    正确),顶多只能修正些显而易见的错误(如:笔误﹑排版错误),至于其

    他进一步的更正﹑补充与诠释,则该以「译注」一节为之。

    「信」做到了之后,「达」则是该追求的品质因子。毕竟译文是给人看

    的,是给一般国人看的,而不是给密码学家看的。想做到「达」,就得勤练

    「基本功」了:句型﹑连接词﹑特殊句构﹑惯用语﹑风俗典故……都是基本

    功的范围,而且是双语皆然。没把这些练熟,就会翻译出我们市面上所见的

    计算机书籍。白居易之诗老妪能解,虽不能至,但总该心向往之吧!至少也该

    让人看得懂那是中国人写的,能通得过「文章作者国籍」的 Turing Test才

    说得过去吧!

    能做到信﹑达之后,已可算是忠实的译品了,读者也不太有认知上的困

    难了(「文字上」没认知困难,但「内容上」则非臣之明所能逆睹也),已

    可算是合格的作品。至于想更进一步追求风格的,就该朝「雅」字迈进。其

    实我习惯把「雅」扩大解释成:合于原作的韵味。就像你不能以《命运交响

    曲》的风格去指挥《田园》一样,若把「哈姆雷特」与「爱玛」说话的语气

    译得一模一样,恐怕莎士比亚与珍‧奥斯汀地下有知,也不会放过你的。

    追求单纯的「文雅」固然是好事,虽然翻译形同是个「再创造」,但若

    因此将原作者所想表现的风韵破坏掉了,那就不算是「翻译」,顶多算是「

    参考某作品」后的自我创作。译者应该认清自己的身份:原著的代言人,应

    该将自我隐藏,而不该一味展现译者个人风格,除非他根本就不想尊重原作

    。所以这篇译文,我尽量维持原作者的风格:平铺﹑简洁,偶尔带点繁复错

    杂,间或参以诙谐。整体说来,你必须逐字细读,才能领会他想表达的技术

    。在适当的地方,我也夹以【译注】来补充些细节。当然,若有任何误译之

    处,完全是我的责任,但我不负任何实质责任(记得该文开头的「责任事项

    」声明吗?)…… :-)

    好不容易把它翻译完了,「自我隐藏」也够久了,终于能在这篇感言中

    揭下面具,痛快淋漓地展现自我……。

    科技类文章还有个令人头痛的问题:专有名词中译。

    底下是本文第三段所提的那篇书评文章中,因杂志版面所限,未予刊载

    的一个前言小段落,姑且放在这儿,当作此问题之我见吧:

    行文中虽无法完全避免,但我会尽量降低中英夹杂的

    比例。有些耳熟能详的英文缩写,会比相对应的中译名词

    简短,如 OOP(对象导向程序设计),我也会采用前者,

    反正文章开头有附缩写对照表。还有一些未有公认中译名

    词的,或未能深契本意的,为避免百家争鸣,我也遵从吴

    大猷先生于联经「理论物理丛书」序言中所提的观点:有

    些名词不译为上。

    将来各位或多或少都会有人从事科技传播的工作,想给您一个建议:中

    文能力真的该加强;至少该把王鼎钧先生的《作文七巧》﹑《作文十九问》

    熟读再三,才不会写出不忍卒睹的中文。行有余力,则以学《文心雕龙》﹑

    《古文观止》矣!有志于翻译者,则该先练练基本功(前述在下的书评中,

    有列举几本书供参考),研读前辈们的宏论,再多加揣摩斟酌,循序渐进,

    必能有成。

    翻译完了之后,有几项收获。比较明显的是:对 C++又多认识了一些。

    以前看这份 FAQ时,「好象」全都看懂了,但是真的要把它翻译出来,就等

    于是强迫自己彻彻底底的把它消化吸收掉,毕竟连自己都半懂不懂的东西,

    怎么再传播出去呢?所以一些以前疏忽掉的地方,这回总算再度认真地研读

    了一番。另一个收获,大概就是中打速度了。以前虽以「纯种注音输入法」

    自豪,但有时对 1234567890 选字键不熟,还得用眼角余光偷瞄一下键盘,

    才能顺利选同音字。经过近七周斯巴达式打字,现在对键盘上方数字键的「

    感觉」好多了……。

    最后要感谢 USENET comp.lang.c++ FAQ 的原作者 Marshall Cline 先

    生,多亏了他,我们才有这么好的 FAQ文件可看;也多亏了他的慷慨同意,

    不才敝人小弟在下我也才能中译之,我也才能有「润键盘」(听过「润笔」

    一词吗)可领……(PS. 退格键坏了,请主编将最后这一句话砍掉……)。

    接下来该翻译什么东西呢?USENET comp.object FAQ?偷看了一下,乖

    乖……有近 600,000 bytes!!! 「祸从口出」﹑「驷不及舌」,前人教训得

    是……上面那段计画当我没说过…… Menu -> Edit -> Undo...。


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/9/19 8:17:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客2
    发贴心情 
    C++语言常见问题解:索引

    第1节:内容介绍

    ----------------

    ⊙1A:「FAQ 书」与「FAQ 文件」

    ⊙1B:目录

    ⊙1C:术语及常用的缩写

    第2节:我该如何参与讨论?(发信之前请务必一读)

    ------------------------------------------------

    Q1:我该在哪个讨论区中发问?

    Q2:我该怎么提出「我的程序有毛病」的问题呢?

    第3节:周遭的﹑管理上的事项

    ----------------------------

    Q3:什么是 OOP?什么是 C++?

    Q4:C++ 的优点是什么?

    Q5:谁在用 C++?

    Q6:有任何 C++ 标准化方案在进行吗?

    Q7:该到哪里索取最新的 ANSI-C++ 标准草案?

    Q8:C++ 对 ANSI-C 回溯兼容吗?

    Q9:多久才能学会 C++?

    第4节:C++ 的基础

    ------------------

    Q10:什么是类别(class)?

    Q11:什么是对象(object)?

    Q12:什么是参考(reference)?

    Q13:如果设定某值给参考会怎么样?

    Q14:怎样才能将参考改设成别的对象?

    Q15:何时该用参考,何时又该用指针?

    Q16:行内函数是做什么的?

    第5节:建构子和解构子

    ----------------------

    Q17:建构子(constructor)是做什么的?

    Q18:怎样才能让建构子呼叫另一个同处一室的建构子?

    Q19:解构子(destructor)是做什么的?

    第6节:运操作数多载

    ------------------

    Q20:运操作数多载(operator overloading)是做什么的?

    Q21:哪些运操作数可以/不能被多载?

    Q22:怎样做一个 "**"「次方」运操作数?

    第7节:伙伴

    ------------

    Q23:伙伴(friend)是什么?

    Q24:「伙伴」违反了封装性吗?

    Q25:伙伴函数的优缺点?

    Q26:「伙伴关系无继承及递移性」是什么意思?

    Q27:应该替类别宣告个成员函数,还是伙伴函数?

    第8节:输入/输出:<iostream.h> 和 <stdio.h>

    ---------------------------------------------

    Q28:该怎样替 "class Fred" 提供输出功能?

    Q29:为什么我该用 <iostream.h> 而不是以前的 <stdio.h>?

    Q30:为什么我处理输入时,会超过档案的结尾?

    Q31:为什么我的程序执行完第一次循环后,会对输入的要求不加理睬?

    Q32:在 DOS 及 OS/2 的 binary 模式下,要怎样来 "reopen" cin 及 cout?

    ========== POSTING #2 ==========

    第9节:自由内存管理

    ----------------------

    Q33:"delete p" 会删去 "p" 指针,还是它指到的资料,"*p" ?

    Q34:我能 "free()" 掉由 "new" 配置到的、"delete" 掉由 "malloc()" 配置到的

    内存吗?

    Q35:为什么该用 "new" 而不是老字号的 malloc() ?

    Q36:为什么 C++ 不替 "new" 及 "delete" 搭配个 "realloc()" ?

    Q37:我该怎样配置/释放数组?

    Q38:万一我忘了将 "[]" 用在 "delete" 由 "new Fred[n]" 配置到的数组,会发生

    什么事?

    Q39:成员函数做 "delete this" 的动作是合法的(并且是好的)吗?

    Q40:我该怎么用 new 来配置多维数组?

    Q41:C++ 能不能做到在执行时期才指定数组的长度?

    Q42:怎样确保某类别的对象都是用 "new" 建立的,而非区域或整体/静态变量?

    第10节:除错与错误处理

    ------------------------

    Q43:怎样处理建构子的错误?

    Q44:如果建构子会丢出例外的话,该怎么处理它的资源?

    第11节:Const 正确性

    ----------------------

    Q45:什么是 "const correctness"?

    Q46:我该早一点还是晚一点让东西有常数正确性?

    Q47:什么是「const 成员函数」?

    Q48:若我想在 "const" 成员函数内更新一个「看不见的」资料成员,该怎么做?

    Q49:"const_cast" 会不会丧失最佳化的可能?

    第12节:继承

    --------------

    Q50:「继承」对 C++ 来说很重要吗?

    Q51:何时该用继承?

    Q52:怎样在 C++ 中表现出继承?

    Q53:把衍生类别的指针转型成指向它的基底,可以吗?

    Q54:Derived* --> Base* 是正常的;那为什么 Derived** --> Base** 则否?

    Q55:衍生类别的数组「不是」基底的数组,是否表示数组不好?

    ⊙12A:继承--虚拟函数

    Q56:什么是「虚拟成员函数」?

    Q57:C++ 怎样同时做到动态系结和静态型别?

    Q58:衍生类别能否将基底类别的非虚拟函数覆盖(override)过去?

    Q59:"Warning: Derived::f(int) hides Base::f(float)" 是什么意思?

    ⊙12B:继承--一致性

    Q60:我该遮蔽住由基底类别继承来的公共成员函数吗?

    Q61:圆形 "Circle" 是一种椭圆 "Ellipse" 吗?

    Q62:对「圆形是/不是一种椭圆」这两难问题,有没有其它说法?

    ⊙12C:继承--存取规则

    Q63:为什么衍生的类别无法存取基底的 "private" 东西?

    Q64:"public:"﹑"private:"﹑"protected:" 的差别是?

    Q65:当我改变了内部的东西,怎样避免子类别被破坏?

    ⊙12D:继承--建构子与解构子

    Q66:若基底类别的建构子呼叫一个虚拟函数,为什么衍生类别覆盖掉的那个虚拟函

    数却不会被呼叫到?

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/9/19 8:18:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客3
    发贴心情 
    C++语言常见问题解:#1~#15

    =======================================================

    ■□ 第2节:我该如何参与讨论?(发信之前请务必一读)

    =======================================================

    Q1:我该在哪个讨论区中发问?

    Comp.lang.c++ 是讨论 C++语言本身最好的地方(譬如:C++ 程序设计﹑语法﹑风格

    )。其它讨论区是用来讨论特定的系统(譬如:MS Windows 或是 UNIX),或是其它

    和 C++语言不直接相关的主题(譬如:怎样使用你的编译器)。底下列出一些非常热

    门的讨论区,并从它们的 FAQs 中摘录些片断,应该能让您明了它们最常讨论哪些课

    题。

    comp.os.ms-windows.programmer.tools

    此区是用来讨论有关 Windows 软件开发系统工具的选择及使用。

    comp.os.ms-windows.programmer.misc

    此乃论及其余 Windows 软件开发之事项。

    [有个 FAQ 列表,列出所有 comp.os.ms-windows.programmer.* 讨论区]

    FAQ 5.7.1. 在 DLL 中存取 C++ 的对象类别

    FAQ 6.1.1. 以 MDI 子窗口做出对话框 [用 OWL]

    FAQ 6.2.1. 把禁能的选项致能起来 [用 MFC]

    FAQ 8.1.5. 使用 windows.h 的 STRICT 符号定义

    FAQ 10. 程序设计参考资料

    comp.os.msdos.programmer

    许多信件都是关于程序语言产品的(主要是 Borland 和 Microsoft)。

    FAQ 301. 怎样才能读取字符而不 [等待] Enter 键?

    FAQ 412. 怎样读取﹑建立﹑更改及删除磁盘标名?

    FAQ 504. 怎样设定 COM 埠,以用它来传输资料?

    FAQ 602. C 程序怎样才能送句柄给打印机?

    FAQ 606. 怎样才能得知 Microsoft 鼠标的位置及按钮状态?

    FAQ 707. 怎样写常驻程序(TSR)工具?

    FAQ B0. 怎样连系 [Borland, Microsoft] 等公司?

    [注意:这份 FAQ 不在 rtfm.mit.edu 里;而在 Simtel

    (譬如 oak.oakland.edu) in /pub/msdos/info/faqp*.zip 以及 Garbo

    (garbo.uwasa.fi) in /pc/doc-net/faqp*.zip]

    comp.os.msdos.programmer.turbovision [Borland 的文字模式应用程序骨架]

    comp.unix.programmer

    FAQ 4.5) 怎样使用 popen() 开启行程以读写之?

    FAQ 4.6) 怎样在 C 程序里 sleep() 一秒以内?

    comp.unix.solaris (包含 SunOS 4.x 和 Solaris)

    FAQ 4) Signal 入门

    FAQ 5) 等待子行程 Exit

    gnu.g++.help

    FAQ: 到哪里找 C++ 的 demangler(反签名编码器)?

    FAQ: 哪里有 Solaris 2.x 版的 gcc/g++ 位文件?

    FAQ: 有 g++ 2.x 的文件吗?

    gnu.g++.bug [g++ 的臭虫列表 -- 请见 g++ 的文件]

    comp.lang.c

    FAQ 1.10: 我搞胡涂了。NULL 保证一定是 0,但是 null 指针却不是?

    FAQ 2.3: 那么,在 C 里头「指针和数组等价」是什么意思?

    FAQ 4.2: [为什么 "printf("%d\n," i++ * i++);" 有问题?]

    FAQ 7.1: 怎样写一个接收不定数目自变量的函数? [stdarg.h 或是 varargs.h]

    FAQ 10.4: 怎么宣告一个指向某种函数的指针数组,而该函数的传回值为:

    指向另一个传回字符指针的函数?

    并请参考看看 comp.graphics、comp.sources.wanted、comp.programming,以及

    comp.object(它的 FAQ 是个很棒的 OOP 入门、术语观念概论文件)。请记住:

    comp.std.c++ 是专门讨论和研议中的 ANSI/ISO C++ 标准方案(下文会提)“直接

    ”相关的事项。

    同时到上述信区和 comp.lang.c++ 去问同一个问题,几乎是没必要的(你是知道的

    ,特定系统信区的读者不用机器语言写程序)。只因你的问题「真的很要紧」,就到

    处发问,是个很坏的习惯。如果你在「正确的」信区没得到回音,且认为你非得在这

    儿发信不可,请至少考虑一下,将这儿的回信重导回原来那个适当的信区。

    在任何信区发问之前,你应当先读读它的 FAQ。你想问的可能就在上面,这样就可省

    下你发信的时间,以及全世界数以千计的人类读你的信的时间。回答已经是 FAQ问题

    的人,可能会因为白白浪费时间而烦扰不已;他们也可能会给你错误或不完整的解答

    ,因为他们也没看过 FAQ。

    「常见问题解答」文件每天 24 小时都可由 anonymous ftp (rtfm.mit.edu 的

    /pub/usenet/comp.what.ever) 或是 e-mail server (寄一则内容为 "help" 的信到

    mail-server@rtfm.mit.edu) 来取得。欲知详情,请见 "Introduction to the

    *.answers newsgroups" 这份文件,它在 news.answers 或 news.announce.newusers

    (这儿还有许多必须一读的文件)中找到。

    ========================================

    Q2:我该怎么提出「我的程序有毛病」的问题呢?

    底下是一些建议,让 comp.lang.c++ 的读者能帮你解决程序设计的问题。

    1. 请读读上一个问题,以确定你的问题是针对 C++语言本身,而和你的程序设计系

    统(譬如:绘图、打印机、设备……)或是编译环境(譬如:「整合环境挂了」

    、「怎样消除xxxx警告讯息」、「怎样连结链接库」)完全无关。如果你想知道

    为什么你 OWL程序中的虚拟函数 CmOk() 没被呼叫到,你的问题可能比较适合放

    在 Windows程序设计的信区。如果你能写个独立的小程序,而它会让编译器产生

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/9/19 8:19:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客4
    发贴心情 
    C++语言常见问题解:#16~#32

    Q16:行内函数是做什么的?

    行内函数(inline function)是个程序代码会塞入呼叫者所在之处的函数。就像宏

    一样,行内函数免除了函数呼叫的额外负担,以增进效率,并且(尤其是!)还能让

    编译器对它施以最佳化(程序融合 "procedural integration")。不过和宏不同

    的是:它只会对所有自变量求一次的值(在语意上,该“函数呼叫”和正常函数一样,

    只是比较快速罢了),以避免某些不易察觉的宏错误。此外,它还会检测自变量的型

    态,做必要的型别转换(宏对你有害;除非绝对必要,否则别再用它了)。

    注意:过度使用行内函数会让程序代码肥胖,于分页(paging)环境下反而有负面的性

    能影响。

    宣告法:在函数定义处使用 "inline" 关键词:

    inline void f(int i, char c) { /*...*/ }

    或者是在类别内将定义包括进去:

    class Fred {

    public:

    void f(int i, char c) { /*...*/ }

    };

    或是在类别外头,以 "inline" 来定义该成员函数:

    class Fred {

    public:

    void f(int i, char c);

    };

    inline void Fred::f(int i, char c) { /*...*/ }

    =============================

    ■□ 第5节:建构子和解构子

    =============================

    Q17:建构子(constructor)是做什么的?

    建构子乃用来从零开始建立对象。

    建构子就像个「初始化函数」;它把一堆散乱的字节成一个活生生的对象。最低限

    度它会初始化内部用到的字段元,也可能会配置所须的资源(内存、档案、semaphore

    、socket 等等)。

    "ctor" 是建构子 constructor 最常见的缩写。

    ========================================

    Q18:怎样才能让建构子呼叫另一个同处一室的建构子?

    没有办法。

    原因是:如果你呼叫另一个建构子,编译器会初始化一个暂时的区域性对象;但并没

    有初始化“这个”你想要的对象。你可以用预设参数(default parameter),将两

    个建构子合并起来,或是在私有的 "init()" 成员函数中共享它们的程序代码。

    ========================================

    Q19:解构子(destructor)是做什么的?

    解构子乃对象之葬礼。

    解构子是用来释放该对象所配置到的资源,譬如:Lock 类别可能会锁住一个

    semaphore,解构子则用来释放它。最常见的例子是:当建构子用了 "new" 以后,解

    构子用 "delete"。

    解构子是个「去死吧」的运作行为(method),通常缩写为 "dtor"。

    =========================

    ■□ 第6节:运操作数多载

    =========================

    Q20:运操作数多载(operator overloading)是做什么的?

    它可让使用类别的人以直觉来操作之。

    运操作数多载让 C/C++ 的运操作数,能对自订的型态(对象类别)赋予自订的意义。它

    们形同是函数呼叫的语法糖衣 (syntactic sugar):

    class Fred {

    public:

    //...

    };

    #if 0

    Fred add(Fred, Fred); //没有运操作数多载

    Fred mul(Fred, Fred);

    #else

    Fred operator+(Fred, Fred); //有运操作数多载

    Fred operator*(Fred, Fred);

    #endif

    Fred f(Fred a, Fred b, Fred c)

    {

    #if 0

    return add(add(mul(a,b), mul(b,c)), mul(c,a)); //没有...

    #else

    return a*b + b*c + c*a; //有...

    #endif

    }

    ========================================

    Q21:哪些运操作数可以/不能被多载?

    大部份都可以被多载。

    不能的 C 运操作数有 "." 和 "?:"(和以技术上来说,可算是运操作数的 "sizeof")。

    C++ 增加了些自己的运操作数,其中除了 "::" 和 ".*". 之外都可以被多载。

    底下是个足标(subscript)运操作数的例子(它会传回一个参考)。最前面是“不用

    ”多载的:

    class Array {

    public:

    #if 0

    int& elem(unsigned i) { if (i>99) error(); return data[i]; }

    #else

    int& operator[] (unsigned i) { if (i>99) error(); return data[i]; }

    #endif

    private:

    int data[100];

    };

    main()

    {

    Array a;

    #if 0

    a.elem(10) = 42;

    a.elem(12) += a.elem(13);

    #else

    a[10] = 42;

    a[12] += a[13];

    #endif

    }

    ========================================

    Q22:怎样做一个 "**"「次方」运操作数?

    无解。

    运操作数的名称、优先序、结合律以及元数(arity)都被语言所定死了。C++ 里没有

    "**" 运操作数,所以你无法替类别订做一个它。

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/9/19 8:19:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客5
    发贴心情 
    C++语言常见问题解:#33~#53

    == Part 2/4 ============================

    comp.lang.c++ Frequently Asked Questions list (with answers, fortunately).

    Copyright (C) 1991-96 Marshall P. Cline, Ph.D.

    Posting 2 of 4.

    Posting #1 explains copying permissions, (no)warranty, table-of-contents, etc

    =============================

    ■□ 第9节:自由内存管理

    =============================

    Q33:"delete p" 会删去 "p" 指针,还是它指到的资料,"*p" ?

    该指针指到的资料。

    "delete" 真正的意思是:「删去指针所指到的东西」(delete the thing pointed

    to by)。同样的英文误用也发生在 C 语言的「『释放』指针所指向的内存」上

    ("free(p)" 真正的意思是:"free_the_stuff_pointed_to_by(p)" )。

    ========================================

    Q34:我能 "free()" 掉由 "new" 配置到的、"delete" 掉由 "malloc()" 配置到的

    内存吗?

    不行。

    在同一个程序里,使用 malloc/free 及 new/delete 是完全合法、合理、安全的;

    但 free 掉由 new 配置到的,或 delete 掉由 malloc 配置到的指针则是不合法、

    不合理、该被痛骂一顿的。

    ========================================

    Q35:为什么该用 "new" 而不是老字号的 malloc() ?

    建构子/解构子、型别安全性、可被覆盖(overridability)。

    建构子/解构子:和 "malloc(sizeof(Fred))" 不同,"new Fred()" 还会去呼叫

    Fred 的建构子。同理,"delete p" 会去呼叫 "*p" 的解构子。

    型别安全性:malloc() 会传回一个不具型别安全的 "void*",而 "new Fred()" 则

    会传回正确型态的指针(一个 "Fred*")。

    可被覆盖:"new" 是个可被对象类别覆盖的运操作数,而 "malloc" 不是以「各个类别

    」作为覆盖的基准。

    ========================================

    Q36:为什么 C++ 不替 "new" 及 "delete" 搭配个 "realloc()" ?

    避免你产生意外。

    当 realloc() 要拷贝配置区时,它做的是「逐位 bitwise」的拷贝,这会弄坏大

    部份的 C++ 对象。不过 C++ 的对象应该要能自我拷贝才对:用它们自己的拷贝建构

    子或设定运操作数。

    ========================================

    Q37:我该怎样配置/释放数组?

    用 new[] 和 delete[] :

    Fred* p = new Fred[100];

    //...

    delete [] p;

    每当你在 "new" 表达式中用了 "[...]",你就必须在 "delete" 陈述中使用 "[]"。

    ^^^^

    这语法是必要的,因为「指向单一元素的指针」与「指向一个数组的指针」在语法上

    并无法区分开来。

    ========================================

    Q38:万一我忘了将 "[]" 用在 "delete" 由 "new Fred[n]" 配置到的数组,会发生

    什么事?

    灾难。

    这是程序者的--而不是编译器的--责任,去确保 new[] 与 delete[] 的正确配

    对。若你弄错了,编译器不会产生任何编译期或执行期的错误讯息。堆积(heap)被

    破坏是最可能的结局,或是更糟的,你的程序会当掉。

    ========================================

    Q39:成员函数做 "delete this" 的动作是合法的(并且是好的)吗?

    只要你小心的话就没事。

    我所谓的「小心」是:

    1) 你得 100% 确定 "this" 是由 "new" 配置来的(而非 "new[]",亦非自订的

    "new" 版本,一定要是最原始的 "new")。

    2) 你得 100% 确定该成员函数是此对象最后一个会呼叫到的。

    3) 做完自杀的动作 ("delete this;") 后,你不能再去碰 "this" 的对象了,包

    括资料及运作行为在内。

    4) 做完自杀的动作 ("delete this;") 后,你不能再去碰 "this" 指针了。

    换句话说,你不能查看它﹑将它与其它指针或是 NULL 相比较﹑印出其值﹑

    对它转型﹑对它做任何事情。

    很自然的,这项警告也适用于:当 "this" 是个指向基底类别的指针,而解构子不是

    virtual 的场合。

    ========================================

    Q40:我该怎么用 new 来配置多维数组?

    有很多方法,端视你对数组大小的伸缩性之要求而定。极端一点的情形,如果你在编

    译期就知道所有数组的维度,你可以静态地配置(就像 C 一样):

    class Fred { /*...*/ };

    void manipulateArray()

    {

    Fred matrix[10][20];

    //使用 matrix[i][j]...

    //不须特地去释放该数组

    }

    另一个极端情况,如果你希望该矩阵的每个小块都能不一样大,你可以在自由内存

    里配置之:

    void manipulateArray(unsigned nrows, unsigned ncols[])

    //'nrows' 是该数组之列数。

    //所以合法的列数为 (0, nrows-1) 开区间。

    //'ncols[r]' 则是 'r' 列的行数 ('r' 值域为 [0..nrows-1])。

    {

    Fred** matrix = new Fred*[nrows];

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/9/19 8:19:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客6
    发贴心情 
    == Part 3/4 ============================

    comp.lang.c++ Frequently Asked Questions list (with answers, fortunately).

    Copyright (C) 1991-96 Marshall P. Cline, Ph.D.

    Posting 3 of 4.

    Posting #1 explains copying permissions, (no)warranty, table-of-contents, etc

    =============================

    ■□ 第14节:程序风格指导

    =============================

    Q81:有任何好的 C++ 程序写作的标准吗?

    感谢您阅读这份文件,而不是再发明自己的一套。

    但是请不要在 comp.lang.c++ 里问这问题。几乎所有软件工程师,或多或少都把这

    种东西看成是「大玩具」。而且,一些想成为 C++ 程序撰写标准的东西,是由那些

    不熟悉这语言及方法论的人弄出来的,所以最后它只能成为「过去式」的标准。这种

    「摆错位置」的现象,让大家对程序写作标准产生不信任感。

    很明显的,在 comp.lang.c++ 问这问题的人,是想使自己更精进,不会因自己的无

    知而绊倒,然而一些回答却只是让情况更糟而已。

    ========================================

    Q82:程序撰写标准是必要的吗?有它就够了吗?

    程序撰写标准不会让不懂 OO 的人变懂;只有训练及经验才有可能。如果它有用处的

    话,那就是抑制住那些琐碎无关紧要的程序片段--当大机构想把零散的程序设计组

    织整合起来时,这些片段常常会出现。

    但事实上你要的不光是这种标准而已。它们提供的架构让新手少去担心一些自由度,

    但是系统化的方法论会比这些好看的标准做得更好。组织机构需要的是一致性的设计

    与实行“哲学”,譬如:强型别或弱型别?用指针还是参考接口? stream I/O 还是

    stdio? C++ 程序该不该呼叫 C 的?反过来呢? ABC 该怎么用?继承该用为实作的

    技巧还是特异化的技巧?该用哪一种测试策略?一一去检查吗?该不该为每个资料成

    员都提供一致的 "get" 和 "set" 接口?接口该由外往内还是由内往外设计?错误状

    况该用 try/catch/throw 还是传回值来处理?……等等。

    我们需要的是详细的“设计”部份的「半标准」。我推荐一个三段式标准:训练﹑谘

    询顾问以及链接库。训练乃提供「密集教学」,咨询顾问让 OO 观念深刻化,而非仅

    仅是被教过而已,高品质的链接库则是提供「长程的教学」。上述三种培训都有很热

    门的市场景况。(【译注】无疑的,这是指美﹑加地区。)接受过上述培训的组织都

    有如此的忠告:「买现成的吧,不要自己硬干 (Buy, Don't Build.)。」买链接库,

    买训练课程,买开发工具,买咨询顾问。想靠自学来达到成功的工具厂商及应用/系

    统厂商,都会发现成功很困难。

    【译注】这一段十分具有参考价值。不过有些背景资料得提供给各位参考。别忘了:

    作者是美国人,是以该地为背景,且留意一下他所服务的公司是做什么的..

    ... :-) 唉!国内有这么多的专业顾问公司吗? :-<

    少数人会说:程序撰写标准只是「理想」而已,但在上述的组织机构中,它仍有其必

    要性。

    底下的 FAQs 提供一些基本的指导惯例及风格。

    ========================================

    Q83:我们的组织该以以往 C 的经验来决定程序撰写标准吗?

    No!

    不论你的 C 经验有多丰富,不论你有多高深的 C 能力,好的 C 程序员并不会让你

    直接就成为好的 C++ 程序员。从 C 移到 C++ 并不仅是学习 "++" 的语法语意而已

    ,一个组织想达到 OOP 的境界,却未将 "OO" 的精神放进 OOP 里的话,只是自欺罢

    了;会计的资产负债表会把他们的愚蠢显现出来。

    C++ 程序撰写标准应该由 C++ 专家来调整,不妨先在 comp.lang.c++ 里头问问题(

    但是不要用 "coding standard" 这种字眼;只要这样子问:「这种技巧有何优缺点

    ?」)。找个能帮你避开陷阱的高手,上个训练课程,买链接库,看看「好的」程序

    库是否合乎你的程序撰写标准。绝对不要光靠自己来制定标准,除非你对它已有某种

    程度的掌握。没有标准总比有烂标准好,因为不恰当的「官方说法」会让不够聪明的

    平民难以追随。现在 C++ 训练课程及链接库,已有十分兴盛的市场。

    再提一件事:当某个东西炙手可热时,招摇撞骗者亦随之而生;务必三思而后行。也

    要问一下从某处修过课的人,因为老手不见得也是个好教员。最后,选个懂得指导别

    人的从业人员,而不是个对此语言/方法论只有过时知识的全职教师。

    【译注】善哉斯言!

    ========================================

    Q84:我该在函数中间或是开头来宣告区域变量?

    在第一次用到它的地方附近。

    对象在宣告的时候就会被初始化(被建构)。如果在初始化对象的地方没有足够的资

    讯,直到函数中间才有的话,你可以在开头处初始个「空值」给它,等以后再「设定

    」其值;你也可以在函数中间再初始个正确的东西给它。以执行效率来说,一开始就

    让它有正确的值,会比先建立它,搞一搞它,之后再重建它来得好。以像 "String"

    这种简单的例子来看,会有 350% 的速度差距。在你的系统上可能会不同;当然整个

    系统可能不会降低到 300+%,但是“一定”会有不必要的性能衰退现象。

    常见的反驳是:「我们会替对象的每个资料提供 "set" 运作行为,则建构时的额外

    耗费就会分散开来。」这比效能负荷更糟,因为你添加了维护的梦靥。替每个资料提

    供 "set" 运作行为就等于对资料不设防:你把内部实作技巧都显露出来了。你隐藏

    到的只有成员对象的实体“名字”而已,但你用到的 List﹑String 和 float(举例

    来说)型态都曝光了。通常维护会比 CPU 执行时间耗费的资源更多。

    区域变量应该在靠近它第一次用到之处宣告。很抱歉,这和 C 老手的习惯不同,但

    是「新的」不见得就是「不好的」。

    ========================================

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/9/19 8:20:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客7
    发贴心情 
    Q54:Derived* --> Base* 是正常的;那为什么 Derived** --> Base** 则否?

    C++ 让 Derived* 能转型到 Base*,是因为衍生的对象「是一种」基底的对象。然而

    想由 Derived** 转型到 Base** 则是错误的!要是能够的话,Base** 就可能会被解

    参用(产生一个 Base*),该 Base* 就可能指向另一个“不一样的”衍生类别,这

    是不对的。

    照此看来,衍生类别的数组就「不是一种」基底类别的数组。在 Paradigm Shift 公

    司的 C++ 训练课程里,我们用底下的例子来比喻:

    "一袋苹果「不是」一袋水果".

    "A bag of apples is NOT a bag of fruit".

    如果一袋苹果可以当成一袋水果来传递,别人就可能把香蕉放到苹果袋里头去!

    ========================================

    Q55:衍生类别的数组「不是」基底的数组,是否表示数组不好?

    没错,「数组很烂」(开玩笑的 :-) 。

    C++ 内建的数组有一个不易察觉的问题。想一想:

    void f(Base* arrayOfBase)

    {

    arrayOfBase[3].memberfn();

    }

    main()

    {

    Derived arrayOfDerived[10];

    f(arrayOfDerived);

    }

    编译器认为这完全是型别安全的,因为由 Derived* 转换到 Base* 是正常的。但事

    实上这很差劲:因为 Derived 可能会比 Base 还要大,f() 里头的数组索引不光是

    没有型别安全,甚至还可能没指到真正的对象呢!通常它会指到某个倒霉的

    Derived 对象的中间去。

    根本的问题在于:C++ 不能分辨出「指向一个东西」和「指向一个数组」。很自然的

    ,这是 C++“继承”自 C 语言的特征。

    注意:如果我们用的是一个像数组的「类别」而非最原始的数组(譬如:"Array<T>"

    而非 "T[]"),这问题就可以在编译期被挑出来,而非在执行的时候。

    ==========================

    ● 12A:继承--虚拟函数

    ==========================

    Q56:什么是「虚拟成员函数」?

    虚拟函数可让衍生的类别「取代」原基底类别所提供的运作。只要某对象是衍生出来

    的,就算我们是透过基底对象的指针,而不是以衍生对象的指针来存取该对象,编译

    器仍会确保「取代后」的成员函数被呼叫。这可让基底类别的算法被衍生者所替换

    ,即使我们不知道衍生类别长什么样子。

    注意:衍生的类别亦可“部份”取代(覆盖,override)掉基底的运作行为(如有必

    要,衍生类别的运作行为亦可呼叫它的基底类别版本)。

    ========================================

    Q57:C++ 怎样同时做到动态系结和静态型别?

    底下的讨论中,"ptr" 指的是「指针」或「参考」。

    一个 ptr 有两种型态:静态的 ptr 型态,与动态的「被指向的对象」的型态(该物

    件可能实际上是个由其它类别衍生出来的类别的 ptr)。

    「静态型别」("static typing") 是指:该呼叫的「合法性」,是以 ptr 的静态型

    别为侦测之依据,如果 ptr 的型别能处理成员函数,则「指向的对象」自然也能。

    「动态系结」("dynamic binding") 是指:「程序代码」呼叫是以「被指向的对象」之

    型态为依据。被称为「动态系结」,是因为真正会被呼叫的程序代码是动态地(于执行

    时期)决定的。

    ========================================

    Q58:衍生类别能否将基底类别的非虚拟函数覆盖(override)过去?

    可以,但不好。

    C++ 的老手有时会重新定义非虚拟的函数,以提升效率(换一种可能会运用到衍生类

    别才有的资源的作法),或是用以避开遮蔽效应(hiding rule,底下会提,或是看

    看 ARM ["Annotated Reference Manual"] sect.13.1),但是用户的可见性效果必

    须完全相同,因为非虚拟的函数是以指针/参考的静态型别为分派(dispatch)的依

    据,而非以指到的/被参考到的对象之动态型别来决定。

    ========================================

    Q59:"Warning: Derived::f(int) hides Base::f(float)" 是什么意思?

    这是指:你死不了的。

    你出的问题是:如果 Derived 宣告了个叫做 "f" 的成员函数,Base 却早已宣告了

    个不同型态签名型式(譬如:参数型态或是 const 不同)的 "f",这样子 Base "f"

    就会被「遮蔽 hide」住,而不是被「多载 overload」或「覆盖 override」(即使

    Base "f" 已经是虚拟的了)。

    解决法:Derived 要替 Base 被遮蔽的成员函数重新定义(就算它不是虚拟的)。通

    常重定义的函数,仅仅是去呼叫合适的 Base 成员函数,譬如:

    class Base {

    public:

    void f(int);

    };

    class Derived : public Base {

    public:

    void f(double);

    void f(int i) { Base::f(i); }

    }; // ^^^^^^^^^^--- 重定义的函数只是去呼叫 Base::f(int)

    ========================

    ● 12B:继承--一致性

    ========================

    Q60:我该遮蔽住由基底类别继承来的公共成员函数吗?

    绝对绝对绝对绝对不要这样做!

    想去遮蔽(删去﹑撤消)掉继承下来的公共成员函数,是个很常见的错误。这通常是

    脑袋塞满了浆糊的人才会做的傻事。

    ========================================

    Q61:圆形 "Circle" 是一种椭圆 "Ellipse" 吗?

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/9/19 8:20:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客8
    发贴心情 
    Q94:Smalltalk/C++ 不同的继承,在现实里导致的结果是什么?

    Smalltalk 让你做出不是子类别的子型别,做出不是子型别的子类别,它可让

    Smalltalk 程序者不必操心该把哪种资料(位﹑表现型式﹑数据结构)放进类别里

    面(譬如,你可能会把连结串行放到堆栈类别里)。毕竟,如果有人想要个以数组做

    出的堆栈,他不必真的从堆栈继承过来;喜欢的话,他可以从数组类别 Array 中继

    承过来,即使 ArrayBasedStack 并“不是”一种数组!)

    在 C++ 中,你不可能不为此操心。只有机制(运作行为的程序代码),而非表现法(

    资料位)可在子类别中被覆盖掉,所以,通常你“不要”把数据结构放进类别里比

    较好。这会促成 Abstract Base Classes (ABCs) 的强烈使用需求。

    我喜欢用 ATV 和 Maseratti 之间的差别来比喻。ATV(all terrain vehicle,越野

    车)很好玩,因为你可以「到处逛」,任意开到田野﹑小溪﹑人行道等地。另一方面

    ,Maseratti 让你能高速行驶,但你只能在公路上面开。就算你喜欢「自由表现力」

    ,偏偏喜欢驶向丛林,但也请不要在 C++ 里这么做;它不适合。

    ========================================

    Q95:学过「纯种」的 OOPL 之后才能学 C++ 吗?

    不是(事实上,这样可能反而会害了你)。

    (注意:Smalltalk 是个「纯种」的 OOPL,而 C++ 是个「混血」的 OOPL。)读这

    之前,请先读读前面关于 C++ 与 Smalltalk 差别的 FAQs。

    OOPL 的「纯粹性」,并不会让转移到 C++ 更容易些。事实上,典型的动态系结与非

    子型别的继承,会让 Smalltalk 程序者更难学会 C++。Paradigm Shift 公司曾教过

    数千人 OO 技术,我们注意到:有 Smalltalk 背景的人来学 C++,通常和那些根本

    没碰过继承的人学起来差不多累。事实上,对动态型别的 OOPL(通常是,但不全都

    是 Smalltalk)有高度使用经验的人,可能会“更难”学好,因为想把过去的习惯“

    遗忘”,会比一开始就学习静态型别来得困难。

    【译注】作者是以「语言学习」的角度来看的。事实上,若先有 Smalltalk 之类的

    对象导向观念的背景知识,再来学 C++ 就不必再转换 "paradigm"--对象

    导向的中心思维是不会变的,变的只是实行细节而已。

    ========================================

    Q96:什么是 NIHCL?到哪里拿到它?

    NIHCL 代表 "national-institute-of-health's-class-library",美国国家卫生局

    对象链接库。取得法:anonymous ftp 到 [128.231.128.7],

    档案:pub/nihcl-3.0.tar.Z 。

    NIHCL(有人念作 "N-I-H-C-L",有人念作 "nickel")是个由 Smalltalk 转移过来

    的 C++ 对象链接库。有些 NIHCL 用到的动态型别很棒(譬如:persistent objects

    ,持续性对象),也有些地方动态型别会和 C++ 语言的静态型别相冲突,造成紧张

    关系。

    详见前面关于 Smalltalk 的 FAQs。

    ===============================

    ■□ 第16节:参考与数值语意

    ===============================

    Q97:什么是数值以及参考语意?哪一种在 C++ 里最好?

    在参考语意 (reference semantics) 中,「设定」是个「指针拷贝」的动作(也就

    是“参考”这个词的本意),数值语意 (value semantics,或 "copy" semantics)

    的设定则是真正地「拷贝其值」,而不是做指针拷贝的动作。C++ 让你选择:用设定

    运操作数来拷贝其值(copy/value 语意),或是用指针拷贝方式来拷贝指针

    (reference 语意)。C++ 让你能覆盖掉 (override) 设定运操作数,让它去做你想要

    的事,不过系统预设的(而且是最常见的)方式是拷贝其「数值」。

    参考语意的优点:弹性﹑动态系结(在 C++ 里,你只能以传指针或传参考来达到动

    态系结,而不是用传值的方式)。

    数值语意的优点:速度。对需要对象(而非指针)的场合来说,「速度」似乎是很奇

    怪的特点,但事实上,我们比较常存取对象本身,较不常去拷贝它。所以偶尔的拷贝

    所付出的代价,(通常)会被拥有「真正的对象本身」﹑而非仅是指向对象的指针所

    带来的效益弥补过去。

    有三个情况,你会得到真正的对象,而不是指向它的指针:区域变量﹑整体/静态变

    数﹑完全被某类别包含在内 (fully contained) 的成员对象。这里头最重要的就是

    最后一个(也就是「成份」)。

    后面的 FAQs 会有更多关于 copy-vs-reference 语意的信息,请全部读完,以得到

    较平衡的观点。前几则会刻意偏向数值语意,所以若你只读前面的,你的观点就会有

    所偏颇。

    设定 (assignment) 还有别的事项(譬如:shallow vs deep copy)没在这儿提到。

    ========================================

    Q98:「虚拟数据」是什么?怎么样/为什么该在 C++ 里使用它?

    虚拟资料让衍生类别能改变基底类别的对象成员所属的类别。严格说来,C++ 并不「

    支持」虚拟数据,但可以仿真出来。不漂亮,但还能用。

    欲仿真之,基底类别必须有个指针指向成员对象,衍生类别必须提供一个 "new" 到

    的对象,以让原基底类别的指针所指到。该基底类别也要有一个以上正常的建构子,

    以提供它们自己的参考(也是透过 "new"),且基底类别的解构子也要 "delete" 掉

    被参考者。

    举例来说,"Stack" 类别可能有个 Array 成员对象(采用指针),衍生类别

    "StretchableStack" 可能会把基底类别的成员资料 "Array" 覆盖成

    "StretchableArray"。想做到的话,StretchableArray 必须继承自 Array,这样子

    Stack 就会有个 "Array*"。Stack 的正常建构子会用 "new Array" 来初始化它的

    "Array*",但 Stack 也会有一个(可能是在 "protected:" 里)特别的建构子,以

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/9/19 8:21:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客9
    发贴心情 
    Q121:「泛型」(genericity)是什么?

    另一种 "class template" 的说法。

    不要和「一般化」(generality,指不要过于特定的解题)弄混了,「泛型」指的是

    class template。

    =======================

    ■□ 第20节:链接库

    =======================

    Q122:怎样拿到 "STL"?

    "STL" 代表 "Standard Templates Library",标准模版链接库。取得法:

    STL HP official site: ftp://butler.hpl.hp.com/stl

    STL code alternate: ftp://ftp.cs.rpi.edu/stl

    STL code + examples: http://www.cs.rpi.edu/~musser/stl.html

    STL hacks for GCC-2.6.3 已经在 GNU libg++ 2.6.2.1 或更新版本里了(可能较早

    的版本也有)。多谢 Mike Lindner。

    ========================================

    Q123:怎样 ftp 到 "Numerical Recipes" 附的程序?

    它是用卖的,把它放到网络上散布是违法的。不过它只需 $30 美元而已。

    ========================================

    Q124:为什么我的执行档会这么大?

    很多人对这么大的执行档感到惊讶,特别是当原始码只有一点点而已。例如一个简单

    的 "hello world" 程序居然会产生大家都想不到的大小(40+K bytes)。

    一个原因是:有些 C++ 执行期链接库被连结进去了。有多少被连结进去,就要看看

    你用到多少,以及编译器把链接库切割成多少块而定。例如,iostream 很大,包含

    一大堆类别及虚拟函数,即使你只用到一点点,因为各组件之间的交互参考依存关系

    ,可能会把整个 iostream 程序代码都塞进来了。(【译注】如果 linker 做得好的话

    ,应该能把完全用不到的组件 object code 砍掉,不随之塞入你的执行档中。)

    不要用静态的,改用动态连结的链接库版本,就可以使你的程序变小。

    欲知详情,请看看你的编译器手册,或是寻求厂商的技术支持。

    ===============================

    ■□ 第21节:特定系统的细节

    ===============================

    Q125:GNU C++ (g++) 把小程序造出大大的执行档,为什么?

    libg++(g++ 用到的链接库)可能在编译时带有除错的信息(-g)。有些机器上,不

    带除错信息地重新编译它,会省下很大的磁盘空间(~1 MB;缺点是:不能追踪到

    libg++ 的呼叫)。仅仅 "strip" 掉执行档,比不上先用 -g 重新编译,再 "strip"

    掉 a.out 档来得有效。

    用 "size a.out" 来看看执行码的程序与资料区段到底占了多大空间,而不要用

    "ls -s a.out" 这种包括了符号表格(symbol table)的方式。

    ========================================

    Q126:有 YACC 的 C++ 文法吗?

    Jim Roskind 是 C++ 的 YACC 文法作者,它大体上和部份 USL cfront 2.0 所实作

    出来的语言兼容(没有 template、例外、执行期型态识别功能)。这份文法有些地

    方和 C++有细小而微妙的差别。

    它可用 anonymous ftp 到下列地方取得:

    * ics.uci.edu (128.195.1.1) in "gnu/c++grammar2.0.tar.Z".

    * mach1.npac.syr.edu (128.230.7.14) in "pub/C++/c++grammar2.0.tar.Z".

    ========================================

    Q127:什么是 C++ 1.2? 2.0? 2.1? 3.0?

    这些不是“语言”的版本,而是 cfront 这个由 AT&T 做出来的、最早的 C++转译程

    式的版本编号。以这编号来“代表”C++ 语言的演进,已经是公认的惯例了。

    “非常”粗略地讲,主要的特征有:

    * 2.0 包含多重/虚拟继承,以及纯虚拟函数。

    * 2.1 包含半巢状 (semi-nested) 类别,及 "delete [] 数组指针"。

    * 3.0 包含全巢状 (fully-nested) 类别、template 和 "i++" vs "++i"。

    * 4.0 将包含例外处理。

    ========================================

    Q128:如果签名编码标准化了,我能否将不同厂商编译器产生的程序代码连结起来?

    简短的回答:可能不行。

    换句话说,有人希望标准化的签名编码规则能并入拟议中的 C++ ANSI 标准,避免还

    要为不同厂商的编译器购买不同版本的对象链接库。然而不同的系统实作中,签名编

    码的差异性只占一小部份而已,即使是在同一个基台(platform)上。这里列出一部

    份其它的差异处:

    1) 成员函数隐含的自变量个数和型态。

    1a) 'this' 有被特殊处理吗?

    1b) 传值的指针放在哪里?

    2) 假设有用到 vtable 虚拟表格的话:

    2a) 它的内容及配置?

    2b) 多重继承时,'this' 在何处/如何调整?

    3) 类别如何配置,包含:

    3a) 基底类别的位置?

    3b) 虚拟基底类别的处理?

    3c) 虚拟表格指针的位置,如果有用虚拟表格的话?

    4) 函数的呼叫惯例,包含:

    4a) 呼叫者还是被呼叫者负责调整堆栈?

    4b) 实际参数放到哪里?

    4c) 实际参数传递之顺序?

    4d) 缓存器如何存放?

    4e) 传回值放到哪里?

    4f) 对传入/传回 struct 或 double 有无特殊的规定?

    4g) 呼叫末端函数(leaf function)有无特殊的缓存器存放规定?

    5) run-time-type-identification 如何配置?

    6) 当一个例外被 throw 时,执行期的例外处理系统如何得知哪一个区域对象该被解

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/9/19 8:21:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客10
    发贴心情 
    == Part 4/4 ============================

    comp.lang.c++ Frequently Asked Questions list (with answers, fortunately).

    Copyright (C) 1991-96 Marshall P. Cline, Ph.D.

    Posting 4 of 4.

    Posting #1 explains copying permissions, (no)warranty, table-of-contents, etc

    =======================================

    ■□ 第17节:和 C 连结/和 C 的关系

    =======================================

    Q105:怎样从 C++ 中呼叫 C 的函数 "f(int,char,float)"?

    告诉 C++ 编译器说:它是个 C 的函数:

    extern "C" void f(int,char,float);

    确定你有 include 进来完整的函数原型 (function prototype)。一堆 C 的函数可

    以用大括号框起来,如下:

    extern "C" {

    void* malloc(size_t);

    char* strcpy(char* dest, const char* src);

    int printf(const char* fmt, ...);

    }

    ========================================

    Q106:怎样才能建一个 C++ 函数 "f(int,char,float)",又能被 C 呼叫?

    想让 C++ 编译器知道 "f(int,char,float)" 会被 C 编译器用到的话,就要用到前

    一则 FAQ 已详述的 "extern C" 语法。接着在 C++ 模块内定义该函数:

    void f(int x, char y, float z)

    {

    //...

    }

    "extern C" 一行会告诉编译器:送到 linker 的外部信息要采用 C 的呼叫惯例及签

    名编码法(譬如,前置一个底线)。既然 C 没有多载名称的能力,你就不能让 C 程

    式能同时呼叫得到多载的函数群。

    警告以及实作相关事项:

    * 你的 "main()" 应该用 C++ 编译之(为了静态对象的初始化)。

    * 你的 C++ 编译器应该能设定连结的程序(为某些特殊的链接库)。

    * 你的 C 和 C++ 编译器可能要是同一个牌子的,而且是兼容的版本(亦即:有相

    同的呼叫惯例等等)。

    ========================================

    Q107:为什么 linker 有这种错误讯息:C/C++ 函数被 C/C++ 函数呼叫到?

    看前两则 FAQs 关于 extern "C" 的使用。

    ========================================

    Q108:该怎么把 C++ 类别的对象传给/传自 C 的函数?

    例子:

    /****** C/C++ header file: Fred.h ******/

    #ifdef __cplusplus /*"__cplusplus" is #defined if/only-if

    compiler is C++*/

    extern "C" {

    #endif

    #ifdef __STDC__

    extern void c_fn(struct Fred*); /* ANSI-C prototypes */

    extern struct Fred* cplusplus_callback_fn(struct Fred*);

    #else

    extern void c_fn(); /* K&R style */

    extern struct Fred* cplusplus_callback_fn();

    #endif

    #ifdef __cplusplus

    }

    #endif

    #ifdef __cplusplus

    class Fred {

    public:

    Fred();

    void wilma(int);

    private:

    int a_;

    };

    #endif

    "Fred.C" 是个 C++ 模块:

    #include "Fred.h"

    Fred::Fred() : a_(0) { }

    void Fred::wilma(int a) : a_(a) { }

    Fred* cplusplus_callback_fn(Fred* fred)

    {

    fred->wilma(123);

    return fred;

    }

    "main.C" 是个 C++ 模块:

    #include "Fred.h"

    int main()

    {

    Fred fred;

    c_fn(&fred);

    return 0;

    }

    "c-fn.c" 是个 C 模块:

    #include "Fred.h"

    void c_fn(struct Fred* fred)

    {

    cplusplus_callback_fn(fred);

    }

    把指向 C++ 对象的指针传到/传自 C 的函数,如果传出与收回的指针不是“完全相

    同”的话,就会失败。譬如,不要传出一个基底类别的指针却收回一个衍生类别的指

    标,因为 C 编译器不懂该怎么对多重及虚拟继承的指针做转型。

    ========================================

    Q109:C 的函数能不能存取 C++ 类别的对象资料?

    有时可以。

    (请先读一读前一则关于和 C 函数间传递 C++ 对象的 FAQ。)

    你可以安全地从 C 函数中存取 C++ 对象的资料,只要 C++ 的对象类别:

    * 没有虚拟函数(包含继承下来的虚拟函数).

    * 所有资料都在同一个存取等级中 (private/protected/public).

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/9/19 8:22:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/11/23 4:22:35

    本主题贴数10,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    218.750ms