蒙面歌王铁扇:为什么C (中文版——感谢waterwalk翻译) - 刘未鹏|C 的罗浮宫 - CS...

来源:百度文库 编辑:九乡新闻网 时间:2024/05/05 03:28:20

为什么C++(感谢waterwalk翻译)

 

刘未鹏(pongba) /文

waterwalk /译

C++的罗浮宫(http://blog.csdn.net/pongba)

 

首先非常感谢waterwalk的辛勤翻译:-) waterwalk把翻译回贴在原文的下面了,为了方便阅读我提取出来编辑以后重发一个帖子。这篇文章原本是想对最近C/C++争论系统的整理一下一些思考的,但由于一开始的时候用英文写了两段,后来就干脆都用英文了,造成很多人阅读的麻烦,在此抱歉。不过好在waterwalk翻译了整篇文章,于是单独贴在这里:-)

 

另,原文在这里。

 

问题

为什么用C++呢? 在你皱着眉头离开之前,试着回答这个简单的问题。效率,是么?人人都知道这个。但情况是,当一个人开始讨论编程语言或与其相关的话题时,他必须要非常明确而有针对性。为什么呢?我来问你另一个问题:如果效率是人们使用C++的唯一理由,那么为啥不直接用C呢?C被认为比C++效率更高(嗯嗯,我知道C没有比C++的效率高多少,所以这里别误解我的意思,因为即使它们二者效率相同,刚才的问题依然存在)。

 

迷思

我知道你又要说“更好的抽象机制”了,因为毕竟C++是要设计成一个更好的C的。C++没有牺牲效率,同时又添加了这么多高级特性。但问题是,“开发者们真的需要这些高级特性么?”。毕竟我们一直听人讲KISS之类的东西。我们也都听到有声称C比C++更KISS所以我们要用C云云。这种持续不断的争论将CC++之间的比较变成了一个大大的迷题(或者说是混乱)。令人惊讶的是,貌似的确有很多人更加倾向于用C,最大的理由就是C++实在是太难用对了。甚至Linus也这么想。

 

这种现象最大的影响就是当人们在C和C++之间权衡时,使人们倾向于使用C。而且一旦人们开始用C,他们很快就适应并满足了(其实,在任何语言乃至任何人类活动中都有此现象,C++亦然,比如常常听到有人说“XX语言我用了这么多年,一直用得好好的”,照这种说法任何图灵完备的语言还不都是能用来编程?)。于是即使他们还没有试试C++,或者他们还没成为好的C++程序员时,他们就开始声称C比C++更好了。然而其实呢,真实的答案往往总是取决于实际情况的

 

我说过“取决于实际情况”了么?那到底实际情况是什么呢?显然,有些领域C是更好的选择。例如设备驱动开发就不需要那些OOP/GP技巧。而只是简单的处理数据,真正重要的是程序员确切地知道系统是如何运转的,以及他们正在做什么。那么写操作系统呢?我本人并没有参与任何操作系统的开发,但我读过不少操作系统代码(大多是unix的)。我的感觉是操作系统很大一部分也不需要OOP/GP。

 

但是,这就表示在所有效率重要的领域,C都是比C++更好的选择么?未必。

 

答案

让我们一个一个来分析。

 

首先,当人们关注效率时,有2种效率——时间效率(例如OS,运行时库,实时应用程序,high-demanding的系统)和空间效率(例如各种嵌入式系统)。但是,这样的分类并不能帮我们决定用C还是C++,因为C和C++的时空效率都很高。真正影响选择语言的因素是业务逻辑(这里的“业务逻辑”并非表示“企业应用业务”)。例如,使用OOP/GP来表达逻辑(或者说代码的结构)好呢,还是就只用数据和过程好呢?

 

据此观点,我们可以把应用程序大致分为两类(当然前提是关注的是C/C++而不是java/C#/ruby/erlang等等):底层应用程序和高层应用程序。这里底层是指像OB/OO和GP没啥用处的地方, 其余归到高层。显然,在所有C/C++应用的领域(这些领域需要C/C++的效率),属于高层的应用有很多(可以看看Bjarne Stroustrup在他主页上的列表)。在这些领域中,抽象至少是和效率一样重要的。而这些正是C++适用的场合。

 

等等还有。即使在程序员不需要高级抽象的领域,也不是就绝对用不到C++。为啥呢?仅仅是因为你的代码中没有用类或模板并不意味着不能用以类或模板实现的库。因为有如此众多方便的C++库(还有即将到来的tr1/tr2),我觉得有充分的理由在这些领域中使用C++——你可以在编码时仅使用C++中的C核心(以任何你喜欢的方式来KISS),同时还能用强大的C++(比如STL容器、算法和tr1/tr2的组件)。

 

最后,我认为人们还常常忽略了一点——有时KISS是建立在抽象上的。我觉得Matthew Wilson在他新书《Extended STL,卷1》的序言中对此做了很好的阐释。他写了2段代码,一段用C,另一段用C++:

 

// in C

DIR*  dir = opendir(".");

if(NULL != dir)

{

  struct dirent*  de;

  for(; NULL != (de = readdir(dir)); )

  {

    struct stat st;

    if( 0 == stat(de->d_name, &st) &&

        S_IFREG == (st.st_mode & S_IFMT))

    {

      remove(de->d_name);

    }

  }

  closedir(dir);

}

 

// in C++

readdir_sequence entries(".", readdir_sequence::files);

 

std::for_each(entries.begin(), entries.end(), ::remove);

 

而在C++09里面更简单:

 

// in C++09

std::for_each(readdir_sequence(".", readdir_sequence::files), ::remove);

 

也就是说,我认为即使一个人在自己的代码里不需要类或模版,他也有理由用C++,因为他用的那些方便的C++库用到了类和模板。如果一个高效的容器(或智能指针)能把你从无聊的手动内存管理中解放出来,为啥还要用那原始的malloc/free呢?如果一个更好的string类(我可没说std::string,地球人都知道那个不是C++中能做出的最好的string类)或正则表达式类能把你从一坨一坨的、你看都不想看的处理字符串的代码中解脱出来,那么为啥还要手动去做这些事呢?如果一个 "transform"(或"for_each")能够用一行代码把事情漂亮搞定,为啥还要手写一个for循环呢?如果高阶函数能满足你的需要,那么为啥还要用笨拙的替代方法呢?(OK,我知道,最后两个需要C++加入lambda支持才真正摆脱鸡肋的骂名——这正是C++0x的任务嘛)

 

总之,我认为KISS并不等同于原始KISS意味着用最适合的工具来做事情,这里最合适的意思是工具能够帮你以尽量直接简洁的方式来表达思想,同时又不降低代码的可读性,另外还保持代码容易理解。

 

真正的问题

人们可能会说,相较于被正确使用而言,C++(远远)更容易被错误使用。而相比而言,C程序的复杂性更容易管理和控制。在C++中,一个普通程序员很可能会写出一堆高度耦合的类,很快情况就变得一团糟。但这个其实是另外一个问题。在另一方面,这种事情也很可能发生在任何一门面向对象语言中,因为总是有程序员在还没弄懂什么是HAS-AIS-A前,就敢于在类上再写类,叠床架屋的一层一层摞上去。他们学会了在一门特定的语言中如何定义类,如何继承类的语法,然后他们就认为自己已经掌握了OOP的精髓了。另一方面,这一问题在C++中更为严重,因为C++有如此众多的偶然复杂性在阻碍设计;而且C++又是如此灵活,很多问题在C++中都有好几种解决办法(想想那么多的GUI库吧),于是在这些选择中进行权衡本身就成了一个困难。C++中的非本质复杂性是其历史包袱使然,而C++0x正是要努力消除这些非本质复杂性(在这方面C++0x的工作的确做得很不错)。对于设计来说,灵活性不是个坏事情——可以帮助好的设计者作出好的设计。如果有人抱怨说这个太费脑细胞了,那可能是这个设计者本身的问题,而不能怪语言。可能就不该让他来作设计。如果你担心C++的高级特性会把你的同事引入歧途,把项目搞砸,那你也许应该制定一份编码标准并严格推行(或者你也可以遵循C++社群这些年积攒下来的智慧,或者在必要时,只使用C++中的CC with class那部分),而不是因为有风险就躲开C++(其实这些风险可以通过一些政策来避免的),因为那样的话,你就没法用那些C++的库了

 

另一方面,其实一个更为重要的问题是一个心理学问题——如果一门语言中存在某个奇异的特性或旮旯,那么迟早总会有人发现的,总会有人为之吸引的,然后就使人们从真正有用的事情中分心出来(这有点像Murphy法则),更不用说那些有可能对真正问题带来(在某种程度上)漂亮的解决方案的语言旮旯了。人们本性上就容易受到稀有资源的诱惑。奇技淫巧是稀有资源,于是奇技淫巧便容易吸引人们的注意力,更别说掌握一个技巧还能够让那人在他那圈子里感觉非常牛了。退一万步,你会发现,即使是一个废柴技巧也能引起人们足够的兴趣来。

 

C++中有多少阴暗角落呢?C++中又有多少技巧呢?总的来说,C++中,有多少非本质复杂性呢?(懂一定C++的人一定知道我在说什么)

 

平心而论,近年来(现代C++中)发现的大多数技巧或(如果你愿意称之为)技术实际上都是由实际需求驱动的,尤其是需要实现高度灵活而又普遍适用(generic)的类库 (例如boost中的那些玩意)。而这些技巧也的确(在某种程度上)提供了对实际问题的漂亮解决方案。让我们来这么想一下,如果你处于一个两难境地:要么用那些奇技淫巧来做点很有用的东西,要么不做这样其他人也就没得用。你会如何选择呢?我知道boost的英雄们选择了前者——不管多么困难多么变态多么龌龊,把它做出来!

 

但所有这些争论都不能改变一个事实我们理应享有一个语言,能够让我们用代码清晰的表达思想。以boost.function/boost.bind/boost.tuple为例,variadic templates可以大大简化这几个库的实现(减至几乎是原先1/10的代码行数),同时代码也(远远)更加简洁易懂。Auto,initializer-list,rvalue-reference,template-aliasing,strong-typed enums,delegating-constructors,constexpr,alignments,inheriting-constructors,等等等等,所有这些C++0x的特性,都有一个共同目的——消除语言中多方面的非本质复杂性或语言中的尴尬之处

 

正如Bjarne Stroustrup所说,很显然C++太过复杂了,很显然人们被吓坏了,并且时不时就不用C++了。但“人们需要相对复杂的语言去解决绝对复杂的问 ”。我们不能通过减少语言特性而使其更加强大。复杂的特性就连模板甚至多继承这样的也是有用的——如果你正好需要它们,而且如果你极其小心使用,不要搬起石头砸自己的脚的话。其实在所有C++的复杂性当中,真正阻碍了我们的是非本质复杂性(有人称之为“尴尬之处”),而不是语言所支持的编程范式(其实也就3个而已)。而这也正是我们应该拥抱C++0x的重要原因,因为C++0x正是要消除那些长期存在的非本质复杂性,同时也使得那些奇技淫巧不再必要(很显然,目前这些技巧堆积如山,翻翻那些个C++的书籍,或者瞅瞅boost库,你就知道我在说啥了),这样我们就能够直观清晰的表达思想

 

结论

C++难用,更难用对。所以当你决定用它时,要小心,要时刻牢记自己的需求所要达到的目的。这里有一个简单的指南:

 

我们需要高效率么?

 

如果需要,那么

 

我们需要抽象么(请仔细思考这一点,因为很难评估使用C++高级特性是否能够抵消误用这些机制的风险正确的回答取决于程序员的水平有多高,遵循哪种编码标准以及编码标准执行得如何,等等)?

 

如果是,那么用C++吧。如果不是,那么,

 

我们需要用C++库来简化开发么

 

如果是,那就用C++吧。但同时必须时刻牢记你在做什么——如果你的代码不需要那些“漂亮的”抽象,那就别试图使用以免陷入其中。别只是因为你在.cpp文件中写代码以及你用的是C++编译器就要用类啊、模板啊这些东西

 

如果不是,那就用C,不过你又会想为啥不仅仅使用C++中属于C的那部分核心呢?还是老原因:人们很容易就陷入到语言的“漂亮”特性中去了,即使他们还不知道这些特性是否有用我都记不清有多少次自己写了一大堆的类和继承,到最后反倒要问自己要这么些个类和继承做什么呀?。所以,如果你能坚持只用C++CC with class的那部分并遵循“让简单的事情保持简单”的理念;或者你需要把C代码迁移到C++中来的话,那么就用C++吧,但要十分小心。另一方面,如果你既不需要抽象机制,也不需要C++库,因为事情非常简单,不需要方便的组件例如容器和字符串,或者你已认定C++能够给项目带来的好处微乎其微,不值得为之冒风险,或者干脆就没那么多人能用好C++,那么可能你还是只用C的好

 

底线是:让简单的事情保持简单(但同时也请记住:简单性可以通过使用高级库来获得);必要时才使用抽象(切记不可滥用;遵循好的设计方法和最佳实践)。

 

--

欢迎参加刘未鹏(pongba)的讨论组,讨论编程相关的任何问题:)

TopLanguage

 

 

本blog相关文章

本blog评论最多文章

  • 你应当如何学习C++(以及编程)(rev#1)(115)
  • 《C++0x漫谈》系列之:Concept, Concept!(75)
  • 《C++0x漫谈》系列之:瘦身前后——兼谈语言进化(69)
  • 争论C++前你应当知道什么(rev#1)(51)
  • 图灵机杂思(rev#2)(33)
  • 为什么C++(中文版——感谢waterwalk翻译)(31)
  • 为什么C++(28)
  • 康托尔、哥德尔、图灵——永恒的金色对角线(rev#2)(28)
  • Track’em Down(27)
  • 关于C++泛型编程的一些杂感(27)
  • boost源码剖析之:泛型指针类any之海纳百川(rev#2)(26)
  • 《C++ Template Metaprogramming》译序——经典之后的经典(24)

本文相关tags

本blog随机文章

  • 你应当如何学习C++(以及编程)(rev#1)
  • 我不想与我不能
  • 并行编程大牛专访
  • 学习密度与专注力
  • 读古龙的岁月(四)
  • 关于刘慈欣的若干个标题
  • TopLanguage小组讨论精选[三](2007.11-2007.12)
  • .NET Generics vs. C++ Templates
  • 《C++ Template Metaprogramming》附录A——预处理元编程
  • 安全的线程同步
  • 《C++ Template Metaprogramming》译序——经典之后的经典
  • 错误处理(Error-Handling):为何、何时、如何

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1785372


[收藏到我的网摘]   [发送Trackback]  刘未鹏发表于 2007年09月14日 16:52:00


特别推荐: 想在这里投放广告?点击查看详情
  • IT 游戏 开发人才专业招聘网站
    每日上万个IT简历更新,快捷有效的招聘求职
  • 非常4+1大学生实训计划,首付6800
    4个月的全套Java技术体系的实训, 1个月的企业大型真实项目的实战开发。
  • 中国SOA应用大调查分析报告
    SOA不仅仅是首席信息官耳熟能详的时髦话语 《信息周刊》和埃森哲的调查显示,一些国内企业出于
  • 如何安全地将Linux root特权下放
    如何改变系统 setuid root 二进制 代码将Linux root特权交给用户
  • 2007年,SOA将如何发展
    权威分析和建议

置顶文章

数学之美番外篇:进化论中的概率论
错误处理(Error-Handling):为何、何时、如何
为什么C++(中文版——感谢waterwalk翻译)
争论C++前你应当知道什么(rev#1)
《C++0x漫谈》系列之:Concept, Concept!
你应当如何学习C++(以及编程)(rev#1)
boost源码剖析之:多重回调机制signal(上)
康托尔、哥德尔、图灵——永恒的金色对角线(rev#2)
图灵机杂思(rev#2)

上一篇: 翻译杂感 | 下一篇: 为什么C++

评论

#   longshanks 发表于2007-09-14 17:25:47  IP: 58.41.31.* 翻得可真不错,写的更是绝了。
我反正相信我们理解不了的东西,对于我们的子辈或孙辈而言,肯定不会是什么复杂的东西。我的儿子就明显比我聪明。:)
要不然,牛顿或莱布尼兹也不应该搞那些那些微积分,来烦恼我们这些后辈。
#   googol 发表于2007-09-14 23:08:26  IP: 221.216.30.* 其实,c有时候一样会陷入奇艺技巧,比如gtk。相比qt,gtk里对内存的控制方法简直就是恼人。虽然qt也好不到哪里去,尤其是qt居然自己实现了一套容器……
#   ProgramJackaroo 发表于2007-09-15 12:35:57  IP: 121.46.119.* 板凳!

复杂的语言。必然也就能处理复杂的问题。。。

深表赞同!!!

“奇技淫巧”一词。。。。感觉有点。。。:)。。。
#   cadinfo 发表于2007-09-15 18:38:45  IP: 218.80.23.* 写得很深奥,关键是知道把简单问题写深奥了,却不知道如何摆脱这种深奥.如果说非要引起编程语言之争的话,那么凭什么就单单提c和C++?把门关起来了,一家人你争我夺,结果却并没有带来分厘的成就.编程语言而已,我用basic,顾名思义,最基本的也很好,关键是看用来做什么.什么膜板不模版,抽象不抽象,如果理解透了OOP的封装,那么讨论何意?
#   Mephisto_76 发表于2007-09-15 23:10:50  IP: 221.6.3.* OOP不是这个世界的唯一,最讨厌一些人整天有事没有的OOP。
#   cadinfo 发表于2007-09-16 00:24:57  IP: 61.173.103.* OOP我个人更加认为是一种思想,是一种理解了系统论而非只知道编程语言的人在面对客观世界时的一种态度.

有些时候参与一些需要对接的项目,最怕的就是扯皮,你不可能对项目中所有的技术都了解,这就有了别的技术人员肆无忌惮的扯皮.面对这种情况,我经常用的一招是告诉他们,要知道你的是个应该封装好了的系统,我并不需要听你罗列那么多的技术细节,把我的输入给你,如果你的输出不正确,那么OK,请修改你的系统,解释给我那么多完全不必要,太抽象了.

这招很管用,很多快退休的博导们和我相处,最怕的就是这招了,他们满腹经纶在OOP的面前显得无比苍白.

这就是我认识的OOP,一种思想而不是一种技术.!!!
#   yhmhappy2006 发表于2007-09-16 16:25:22  IP: 60.12.8.* 请教刘老师,c++0x中加入自动垃圾收集清理了吗?
我觉得这是c++发展的关键!愚见,不要笑话俺,^_^
#   pikecabbage 发表于2007-09-16 19:21:48  IP: 60.168.227.* 这篇文章 翻译的很好,写的更棒,最欣赏的一句话就是
“我都记不清有多少次自己写了一大堆的类和继承,到最后反倒要问自己“要这么些个类和继承做什么呀?“
感觉你写的文章都很温柔。
#   turingbook 发表于2007-09-17 01:04:38  IP: 221.223.35.* 强文啊。感觉功力越来越精进了。

Amazon上《C++编程规范》一书的human readable链接真绝:Coding-Standards-Guidelines-Practices-Depth

衷心地铜臭一下:没有读过这本书的C++ Fans,赶快去买吧。
http://dearbook.com/book/91309
#   Jofee 发表于2007-09-17 15:58:20  IP: 220.201.36.* 请教刘老师,c++0x中加入自动垃圾收集清理了吗?
我觉得这是c++发展的关键!愚见,不要笑话俺,^_^
----------------------------------------
除了垃圾收集,加入什么都无所谓,
我就烦垃圾收集,因为他使我没法完全控制我的程序运行。
#   pongba 发表于2007-09-17 17:33:57  IP: 222.94.3.* to yhmhappy:
会加入的,详见:
http://blog.csdn.net/g9yuayon/archive/2007/07/23/1702694.aspx

to Jofee:
C++09的垃圾收集将是完全可选的。
#   whykarmen 发表于2007-09-18 18:51:10  IP: 222.66.2.* To pongda:
我从前也是C++的fans,也曾经在“语言律师”的道路上走过相当长的时间,时过境迁,如今回头去看,却有很多迷茫,在这次C/C++的大混战中也看到了很多高手的意见,本来无意参与,但是看到你的why C++,有些问题想向你请教一下。千年潜水,希望首次冒泡不会被无视:)
对《why c++》这篇文章,首先存疑的是,我个人认为,在靠近底层的开发上,C和C++的效率事实上还是有一定差距的,而不是相差无几,1。时间效率上,C的唯一软肋就是函数调用,std::sort击败qsort被cpper宣扬了无数次,template能够(而不是必然)展开调用从而提高效率,但是C++效率上的最大弱点--临时对象造成的问题更为严重,这一点我想你应该能同意,至于虚函数其实C和C++半斤八两,当然,EH和RTTI的效率不彰也是事实了,不然一些嵌入式环境下也不会裁减C++了。2。从空间效率上,C++运行时需要的空间要大一些,以至于在一些嵌入式环境中不可接受,template导致的空间膨胀就不说了,为EH保留的空间也不说,全局变量初始化列表也不说,单只虚表就不是小负担,考虑32位环境下一个应用中有100个类,每个有100个虚汗数,这样光虚表就4*100*100=40K bytes,好吧,我们可以八这些都去掉,size下来了,可那干吗还要用C++呢?C不是更好?3。从编译效率上,相对于C,C++的编译速度臭名昭著,大项目(典型的,比如OS,明说吧,linux)用C++编译,可以去死了。另一个重要的原因,也许是最重要的,C简单直接,清晰可控,这一点在那些需要绝对控制力的底层应用中至关重要,你总不至于在一个系统中断中还要考虑代码是不是会产生临时对象,这临时对象是不是会偷偷摸摸调用new或者allocator,而后者究竟是调用malloc还是sys_alloc还是pool.alloc呢?这些隐藏的东西是为了更好的抽象,而抽象在需要抽象的时候是好的,但是在不需要的时候,是累赘,甚至损害。在底层,抽象恰恰不必要。好吧,你说我们还可以用那么多的库,但是亲爱的,你见到哪个C++的著名库里不是多态异常模板满天飞的?那些不正是底层不需要乃至避之不及的吗。所以,在真正意义的底层领域,C++比C来说,逊之远矣。
软件开发从根本上来说属于工程而非科学领域,这决定了凡事以实用为指导原则,说白了,软件是为了解决问题的。这里重点关注两个需求,一是特别复杂的系统,这时成本,复用性等不是那么重要;二是追求开发效率。需要注意的是系统的复杂性与规模没有必然关系,如果各子系统之间没有复杂的联系,那么即使有一万个子系统,复杂度仍然不会高于O(N),甚至就是O(1),人类处理复杂性问题的唯一手段是抽象,而抽象从根本上说是分析和设计问题,在思维层面如果能解决复杂性问题,才能谈到用什么语言或工具来实现,如果不能在思维层面解决的,语言又能作甚么呢?当将抽象付诸实现的时候,提供(相关领域)更高的抽象层次的语言或工具当然更理想,C++明显不是那些DSL甚至java,C#们的对手,在这里,C++相对于C的优势只是编译器提供的一些语法上的帮助,可是能够解决这种复杂度的设计师,应该不会被束缚在某种特定语言上了,C也未尝不可。无论如何,这里C++也许比C有一点优势,不多的一点。除了这些极端复杂的系统,更多的,应该说多数系统都是没那么复杂,更需要快速开发,成本低,快速更新的,那么脚本或者动态语言,尤其是DSL当然更适合。C++明显不适合。
这里插一句,O
#   whykarmen 发表于2007-09-18 18:51:30  IP: 222.66.2.* 这里插一句,OO不是银弹,这个世界,不是OO的,或者说,不止是OO的。OO,只是诸多选择中的一种。
我无意评判C++与C谁更优秀,他们有不同的适用领域,但是C++明显处于尴尬的境地,他只适合要求兼顾抽象和效率,并且不注重快速开发的地方。在中间地带生存,就像蝙蝠,总是尴尬的。好吧,也许你会用http://www.research.att.com/~bs/applications.html来教育我,有这么多的大项目,可是仔细看看,其中“真正”称得上用C++的“底层”应用有多少?不要认为用C++的编译器编译出来的一定是C++代码,还可以是C的呢。多数是应用层或应用库。按我愚见,目前C++的常用领域是GUI、图像处理和游戏。
最后,我想请教一下《why C++》中至关重要的“非本质性复杂性”如何定义?C++或者说软件开发的“本质复杂性”是什么?如何解决?用C++能够解决么?恕我直言,此文规避了核心问题,所以失去了价值。
谢谢。
#   whykarmen 发表于2007-09-19 10:57:30  IP: 222.66.2.* 补充,make simple things simple, make hard things possible. C++不太容易make simple things simple,对于hard things,也未必是唯一合适的。一直以来,cpper都坚定的宣称C++支持PO/OB/OO/GP等多种范式,表现力无与伦比,能让你做任何你想做的。这种说法也对也不对,那些个范式,都是学理上的概念,必须对解决实际问题确有帮助才能拿出来炫耀,而OO和PO首先是设计思想,其次才是编程方法,所以你不能说C就不支持OB和OO,只是费些周章罢了。任何一个支持OO的语言(如java)当然也支持PO和OB。至于GP,似乎目前主要就是以stl和boost为代表的一些库,真正在应用中的适用范围并不广,想想也是,你不可能用GP写一个付款流程或者进程调度器,也不要提loki基于策略的设计方法,结构与策略分离,本来就不仅应用于GP,而且谁真的在实际应用中用template来作策略了?就算template被证明图灵完备,它的使用范围仍旧是有限的。最后说说表现力,所有真正意义上的“通用语言”一定都具有足够强的表现力,我说C和汇编的表现力也是无与伦比呢。但是现实世界中通用语言越来越少了,至少C++之后似乎没有成功的通用语言了,为什么?因为这个世界越来越走向专业化,社会分工越来越强,什么都能作必然什么都不如专业语言,即使是需要跨越多个领域的应用,也大可以组合多个DSL,而不需要用C++吭哧吭哧蛮干,C++的开发效率实在是orz。这一点上C不同,因为它是(唯一成功的?)对现有冯诺伊曼计算机体系结构的清晰而直接的(高级语言)映射,所以我们可以大胆预测它不会在冯诺伊曼机器被淘汰之前灭亡。C++什么都想作,所以越来越大越复杂,就像恐龙。这么说回来,C++作为一门高级的教学语言还是很合适的。
#   whykarmen 发表于2007-09-19 11:07:09  IP: 222.66.2.* 我说了这么多C++的缺点,不是为了攻击C++,而是我也想知道:WHY C++? Why not C and java and python and DSLs?谁能告诉我?
#   xyz 发表于2007-09-19 13:13:02  IP: 172.17.32.* to whykarmen:
我觉得,你所说的C++的各个方面的问题,如果用C也未必好到那里去。

1、首先,是临时对象的问题,在C语言中也必然存在,只不过有时候C++里边的对象大了一点儿,如果有虚函数的话(多一个指向虚函数表的指针),而且有容易将C++的对象写成巨无霸。
2、RTTI可以关闭,不能说C++就RTTI,就必然被使用,但是如果C语言需要模拟这种特性,它必然也会付出同样的代价。
3、EH,同样EH也可以被关闭。但在效率不是绝对重要的情况下,关闭异常是愚蠢的,每个函数都想WIN32 API一样,返回BOOL,或者其它类型?首先,程序员可能不买你的仗,它不去检查。其次,是对美学对艺术的玷污。
4、关于虚函数和模板的开销,C语言同样不可避免。我不是说C语言中有虚函数和模板,我说的是C语言中如果要实现在运行时确定的东西,它必然也要去创建查找表,查找表必然需要占用时间和查找空间(不要告诉我查找表是不需要的)。再说说模板,对一个算法来说,C++模板会对不同的类型在编译的时候自动生成相应的代码,而C语言如果要使一个算法适应不同的类型的话,它必须让程序员把这些代码愚蠢的重复这么多次,只因为它们类型是不同的,结果两者占的空间也是相同的。

下面,我说说C++有而C没有的东东。
1、构造函数和析构函数。即使没有其它所有的东东,这一点也是C++比C优越得多的地方,而且这一点是C++比所有其它的编程语言都要强的一个地方。很多C程序员的代码不经意就有资源泄漏(包括内存),而且为了确定性释放资源,采用了很丑的语法,往往伴有goto字样。
2、template,除了用宏或者重复代码之外,C语言与之相比只能说太差,而且泛型也改变了人的设计思维。
3、函数重载(基于参数类型或者参数个数的不同)。这一点上,C只能靠给函数再起一个名字了。其实再起一个名字,本身无所谓,但是造成的代码风格不一致确是个大问题。因为面对一定风格的东西,人们的生产效率是最高的(这也是现代流水线产生的根本原因)。
4、缺省参数。在编码的过程中,有时我会发现自己的某个函数需要一个额外的参数,来实现更好更合理的逻辑。在C++中,我只需要加一个参数,给它一个缺省值,让它们符合以前使用该函数的代码。在C语言中,呵呵,你就改吧。
5、标准库。在C语言中也有一定的标准库,完成许多工作。但是C++标准库达到的境界,远非C语言所能比。其实使用C++你不一定要用面向对象的东西,有时候我就希望用一个现成的hash表又或者一个现成的sort功能。这个时候C语言就不能给我更好的帮助了。
6、面向对象。某些时候,在C语言用switch..case建立一个庞大而且僵化的依赖于类型的table时,C++用巧妙的运行时多态解决了(也可以是泛型,看具体情况)。
6、还有其它很多比较小的方面,包括更强的类型检测等等。

或许C确实比C++快那么一点,内存占用也小那么一点点,但是我认为在大部分情况下,C++带来的便利和优越性是值得我们去交换的。

关于效率,C++好像出了一个性能技术报告,你可以去看看。确认一下到底C++比C慢在什么地方以及慢了多少,如果用C来达到相同的效果,需要多大的努力以及多大的开销。

现代所有的编译器都会对代码进行大量的优化,包括局部优化和全局优化,我们人在这方面通常是比不上机器的,是吧?可能你说的临时变量的
#   xyz 发表于2007-09-19 13:13:35  IP: 172.17.32.* 问题,很多优秀的编译器已经通过优化解决掉了,这个时候C的效率只是一个心理优势。

C在绝对需要效率和内存及其紧张的环境中是王者,但是大部分的时候它不是。因为更多的地方对内存要求不那么苛刻,对系统要求也不是那么实时,相反对开发的效率要求倒是很高。这个时候C就未必是比C++更好的选择了。

C++有很多很多的东西,看起来杂乱无章,很恐怖。但是,C++不是要求你每时每刻都要用上所有的这些东西,也不是把所有这些东西都强加到你的身上。她只是给了你一个有很多工具的工具箱,如何使用还是在你。
#   sevencat 发表于2007-09-19 14:16:39  IP: 124.243.200.* C++的效率大部分不是因为单独的代码段,而是因为风格。比如说你用C喜欢用printf,用C++为了酷就用stream了。
用C你直接操作字符串,用C++你就用string了。
用C你直接写链表,用C++你用std::list,这样你的效率就降下来了。
用C++你可能想用异常处理。
要是单纯的一样的代码,效率没什么差别。

在现实的程序里,用C++写的程序就基本上比C的效率要低也是这个原因。C++也可以写出效率很高的程序,但大部分情况下,设计差不多的情况下,是会比C低的,因为你抵制不住C++的库以及C++的设计思路的诱惑。
#   whykarmen 发表于2007-09-19 17:44:15  IP: 222.66.2.* TO xyz:

你说的都有道理,我们可以再深入讨论一下,

首先声明,我无意比较C与C++哪个更接近上帝,我所针对的问题是:其他语言,包括C,

都有自己明确的领地,但是C++处于不上不下的尴尬境地。那么C++的路在何方呢?所以我也问

WHY C++? 当然我的问题和pongda的本意是迥然不同的了。
不过既然已经扯上了C,那么就逐条过招吧。

1。关于临时对象,我指的不仅是返回一个对象的问题,而且C++的临时对象经常会附带一次到

多次ctor或copy ctor以及dtor,而且更进一步说,由于语言风格和习惯的不同,C程序员很少

会让函数返回一个对象,而是作为返回参数传进去,所以临时对象这个C++中显著的问题在C中

似乎从来不是一个问题,也就称不上“在C语言中也必然存在”。在这里让我不厚道的攻击一

下,C++一直想进入fortran的领域却从未成功的主要原因就是临时对象,比如:matrix

operator+(const matrix& mtx) const;,C通常写成类似void matrix_add(matrix* out,

const matrix* in1, const matrix* in2);的形式;

2。关于RTTI,通常嵌入式等底层开发环境,RTTI都是关闭的,使用C模拟需要的RTTI的开销通

常小的多,因为可以定制。我使用C++的RTTI有一次不愉快的精力,程序交给MS去测试的时候

,他们说RTTI占了25%的运行时开销,那个软件是XBOX游戏,代码在1十几w行,不大,只是为

了说明不是刻意构造以诋毁异常的程序;

3。EH,事实上底层开发也经常关闭异常,C++异常的一个缺点在于它违背了一直以来承诺的“

如果你不用到,就不需要额外代价”的原则,在这些领域,程序员当然应该自己检查返回值,

不检查也可以,如果老板没意见的话。当然,返回值确实有它的问题,但是可以看到连linux

和windows源代码都是如此。至于美学和艺术,呵呵,我一向认为计算机是实用学科,没了实

用性,其他的一文不值,而一个软件能在稳定性/扩展性/可读性/可维护性/伸缩性/效率等方

面做的好的话,本身就应该是让人觉得舒服的,所以就不要往美学和艺术上靠了吧。对于工具

而言,额外的美也许意味着设计过度。就像一把刀,如果在刀身上雕些花样,只会影响刀的强

度和空气动力参数;

4。关于虚函数,如果C需要的话只能模拟,但是并不需要查找表,就像C++也不需要查找表一

样,可以使用索引直接定位到。这个我说了C和C++是半斤八两。至于模板,确实是好东西,很

好,C程序员应该会羡慕,但是没有怎么办呢?如果我们看看实际的项目代码中,不太会出现

诸如template T abs(const T& t);的需求,所以也不是
#   whykarmen 发表于2007-09-19 17:45:01  IP: 222.66.2.* 所以也不是那么重要,即使有,并

且也不愿意重复写代码,那么召唤macro吧,不要对宏这么抵触,boost中不也有很多宏吗?宏

其实并不危险,主要的麻烦是难以调试,所以你会看到C的一种做法是debug用函数,release

用宏;

关于C++有而C没有的东东:
1。构造和析构真是好东西,非常好,如此只好。以至于B.S.大神说:资源获取即初始化

(resource acquisition is initialization),是的,这无比的正确。如果C有这个就好了

。事实上这是我觉得C比C++唯一缺少的重要特性。释放资源通常只能靠C程序员的细心,以及

那个我并不认为丑陋的goto,在这一点上,我同意你的看法;
2。template,前文应该有了足够的讨论,不再多说,只是我认为泛型并不是革命性的变化(

即使有也只存在于某些利益集团中,我不是说jjhou哦,呵呵);
3。函数重载,赎我愚钝,真的没感觉到风格不一致的问题。反倒是觉得当重载函数过多时,

你自己都会分不清哪个是哪个了,举个例子,3D中有时需要计算各种图形的碰撞,有球体,圆

柱体,长方体,托球体,直线,线段,点等等,大牛们用双分派来(不圆满的)解决这个问题

,象我的水平当然没办事写双分派,怎么办那?如果是函数重载,都叫collision_dector,搞

道后来你自己都不知道哪些你实现了,哪些不需要实现,每个函数的参数顺序怎样,还不如:

collision_detect_sphere_box,一目了然;
4。缺省参数,关于这个,我恰好有不同的体会。缺省参数的主要缺点是它在你背后做事情,

而让你丢失了一些控制权,如果不小心的话,有可能改变原有程序的语义,从而造成隐藏的

bug。另外,对于看代码的人来说,由于省略了一些参数的书写,反而会让你不明了那些被省

略参数的意义了,你还是得去查声明。个人感觉缺省参数适合于有太多参数的函数,而且多数

的参数的取值都有习惯的缺省值,比如windows的CreateWindow,这时用缺省参数省一些击键

数目,所以不是什么了不得的特性。如果你真的修改了函数规格,那么自然应该好好衡量是否

会影响以后的调用,而不只是价格缺省参数了事。有种不太完美的办法来,函数参数不要使用

多个标量,可以使用struct,这样当参数改变的时候,不需要改变调用点的代码,底层处理好

了。最后,我觉得你举的例子不正确:如果你不想更改老代码,那么直接该老代码调用的那个

函数的实现好了,新的代码再去调用新的函数,在这一点上,C不失一分;
5。标准库。这个世界上C完成的系统应该比C++多吧,那么这么多系统难道不需要自己的库吗

?他们当然已经被实现(很多次)了,比如glib中就有hash,C标准库当然也有qsort,至于说

道境界,恩,cpper喜欢拿这个说事,事实上stl的六大组件:

iterator,
#   danath 发表于2007-09-19 17:45:11  IP: 58.247.121.* sevencat:

用到你说的那些C++ feature是因为风格?为了酷?难道你看不到程序从中得到的实实在在的好处吗?
#   whykarmen 发表于2007-09-19 17:45:24  IP: 222.66.2.* 事实上stl的六大组件:

iterator,alloctor,container,algorithm,adaptor,functor,C一样可以都可以实现,真的,

都可以,虽然可能要使用宏,但是境界丝毫不差。另外,C++标准库也不是那么完美,

iostream和basic_string也许应该列为反面教材,并且付出了效率下降的代价,尽管它标榜的

就是极度的效率:);
6。强类型检测,感觉这部分C++和C是完全兼容的,说C不好,C++也跑不了,而且现在的C对类

型要求的也严一些了,相信严肃的C程序员都不会在这上面栽跟头;

至此,除了构造函数和template,看不出C++的优越性在哪里,便利确实好一些,但是不

足以抵消偷偷摸摸做的那些事情的危害。
在C的领域里,“C确实比C++快那么一点,内存占用也小那么一点点”,真是C++的软肋。

令,不知道你指的性能技术报告是不是《Technical Report on C++ Performance n1396

》,很惭愧,还没看过,我会仔细学习一下,如果不是,请告诉我该报告的链接好么?谢谢。

最后,非常赞同sevencat的观点,C++的问题在于它自身的风格,它野心太大,太复杂,从而容易被误用,在抛弃了C的简单直接之后,事实上在思想上它已经和C分道扬镳了,所以C从语法上是C的超集,语义上则是全新的语言。当然你可以说误用的程序员自己不好,但是这门语言真的可以独善其身吗?抛弃了多数程序员,也就被多数程序员抛弃。那么,我还是想问:C++的领地在哪里?WHY C++?
#   whykarmen 发表于2007-09-19 17:47:18  IP: 222.66.2.* CSDN的发言还有这么小的字数限制吗?害的我一篇帖子要分三次发,孟岩大人该管管了吧?
另外pongda怎么还没出现?郁闷ing。。。
#   pongba 发表于2007-09-19 20:42:18  IP: 222.94.3.* whykarmen:
不好意思:-) 这两天在做一个presentation,忙死了,看贴工夫都没有,请移驾我的讨论组:
http://groups.google.com/group/pongba
上面有许多兄弟,而且讨论质量都很高,目前有一些话题也许跟你的思考有关联:-)
#   yhmhappy2006 发表于2007-09-19 21:41:21  IP: 60.12.8.* 精彩
#   xyz 发表于2007-09-19 22:01:10  IP: 221.6.3.* 呵呵,理越辩越明。

我们的分歧总是存在的,而且都有自己的理论依据,或许是工作环境不同所致吧。我们都在夸大自己看到的优势,然后把自己看到的缺点情描淡写。

比如性能。性能问题在任何系统都存在,只不过相对于达到某个目标付出的代价值不值得的问题。我学的是机械,当时老师讲过,任何零件当然是越精密越好,但是到了一定的粗糙度以后,若再想提升一点,都要付出10倍或者更多的成本,当然有些地方需要这个精度的,成本肯定必须出。不过如果可以有些地方没有这么强的要求,那还是省一身吧。同样的问题也适用与工程设计的安全系数以及其它绝大多数方面。

如果性能至关重要,确实有必要采用C风格的编码方式和惯用法,甚至可以内嵌汇编代码来解决。我很少做这种性能要求极强的开发,所以我体会不深。但是我觉得C语言不是全部用来做这个工作的,他也被广泛用于编写其它用途的代码,比如应用程序服务器,这个时候性能固然重要,但应该不是唯一重要的,重要的还有系统的稳定和资源的实时回收,以及对并发的支持程度、可升缩性等等。

我觉得对性能要求的理解导致了我们之间的根本分歧。
#   xyz 发表于2007-09-19 22:20:18  IP: 221.6.3.* 硬要刨根问底的话,C++在普遍性能上肯定不会快过C。但也不是绝对的,需要具体问题具体分析。

比如我用以效率低而闻名的python读取一个列表文件,然后对其进行唯一性筛选,由于其内置了hash表,通常作为刚入门的我写的代码就会比刚入门的C或者C++的程序员的代码效率要高,而且编码效率要高很多。

这个例子说明语言本身的好坏是一回事儿,一个人的功力又是一回事儿。我用C语言并不一定能写出大师级的hash表,也未必能写出足够稳定的容器和算法,并且效率和泛用性都很强,所以有时候我就懒一点,用C++了,而且在我的工作环境中,是允许这样行事的。
#   刘未鹏 发表于2007-09-20 20:42:40  IP: 222.94.3.* CSDN上很难见到whykarmen和xyz、sevencat这样的理性辩论者:-),就连Linus那个新闻组上的发言者,我看也很有局限性。最近boost.devel组上有人发帖提到linus的话,有人一语就点中要害了:Linus人家那话本来就是针对他的开发领域说的,而听者却把这个前提给忽略掉了。的确有这样的底层领域,不仅OO和GP起不到作用或只起到微乎其微的作用,而且有时候就连用用标准库还要担心库做的幕后工作,比如对象生命期和内存控制问题。只不过不要把这个逻辑拉升到太远,除此之外,效率重要的领域,还有很多,不代表那些领域就有这些严格的限制啊。

关于各位说的几个问题:模板,异常,虚函数表,RTTI,其实这几个问题由来已久了,是属于对C++不正确的认识导致的误解。

B.J提到在九几年的时候还有人认为模板会损伤运行时效率呢...另一方面,在模板的空间效率上面,并不会导致代码膨胀,那些实例化出来的模板实例,都是要用的,你不用模板,one way or another,你总归还是要写出一个实例来,不管是用宏还是什么的。此外,模板还有一个性质就是没用到的不实例化,如果一个类模板里面的某个函数没用到,那就不会占代码空间,所以还反而节省了空间。

至于异常,目前的编译器实现已经能够做到happy path上0开销了。

RTTI我不知道你是怎么用的,怎么开销那么大,如果一个程序中太多的type-switch的话,几乎肯定是设计问题,应该诉诸多态解决的。

虚表的问题有那么严重吗?除非继承实在太多了,而继承太多并不是好事,往往就意味着设计的问题。现代C++风格并不是传统的基于接口和继承来进行动多态的,更多的时候提倡尽可能利用静态多态,充分利用静态类型信息。

关于“非本质复杂性”,我想不用多说吧,整个一本《Imperfect C++》几乎都是讲如何对付C++里面的非本质复杂性的。早期的还有《C++ Gotchas》。就拿现代的C++模板技术来说,整个C++模板技术体系就是建立在tricks的基础之上的,而并非语言的直接支持(D语言在这个上面做了直接支持,大大简化模板编程)。此外那些名字查找啊,语法枝节啊,什么的问题就不一一说了。我认为“Effective C++”也是靠介绍如何workaround语言中的非本质复杂性得以受欢迎的。再进一步,《设计模式》里面也有好些模板对付的也是非本质复杂性,如二进制兼容性。
#   middle 发表于2007-10-07 13:32:10  IP: 61.149.171.* 人们比较语言,往往是在比较runtime(当然,C vs. C++不在此列)。现在大家已经倾向于认同:不同runtime之间的比较没有孰优孰劣,只有侧重点不同。

但是,在一个完全相同的runtime环境下同时并存两种主流的语言,只有C/C++这种情况了,而且二者的语法还十分接近。所以C vs. C++是一个很特殊的现象,不能与其他语言之间的比较相提并论。

C/C++的问题在于,两种语言没有拉开足够的距离。这个问题导致了“视具体问题选择语言”这个基本原则在C vs. C++这个问题上根本就成为一句废话。

问题在于,在C和Java-like(也可以说是managed runtime)语言之间没有足够的“距离”容纳另一种语言(尤其是OOP-language)。
#   icosagon 发表于2007-12-02 22:40:02  IP: 219.134.169.* C pk C++ 实际是两种软件开发模式PK
让一个c++的开发人员不用class? 或者让一个c开发人员去适应OO?
习惯不是那么容易改变的,尽管c++不只是提供了OO

OO对于粒度控制并不能像c那样随心所欲,而c那种过程化的语言对于数据抽象也无从着力,尽管可能通过良好的设计来达到目的,但那没有长年的经验是不可能做到的,
能同时做到这两者的程序员个人私底下认为没有
#   koc105 发表于2007-12-05 15:27:37  IP: 202.69.89.* 欢迎光临我的编程网 http://www.kingofcoder.com

外国技术文章专区现在开张 - 目的是提供一个统一的地方, 给各编程爱好者阅读欣赏外国先进的编程技术
http://english.kingofcoder.com