`

为什么C++(中文版——感谢waterwalk翻译)

 
阅读更多

为什么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之类的东西。我们也都听到有声称CC++KISS所以我们要用C云云这种持续不断的争论将CC++之间的比较变成了一个大大的迷题(或者说是混乱)。令人惊讶的是,貌似的确有很多人更加倾向于用C最大的理由就是C++实在是太难用对了甚至Linus也这么想

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

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

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

答案

让我们一个一个来分析。

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

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

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

最后,我认为人们还常常忽略了一点——有时KISS是建立在抽象上的。我觉得Matthew Wilson在他新书《Extended STL1》的序言中对此做了很好的阐释。他写了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的代码行数),同时代码也(远远)更加简洁易懂Autoinitializer-listrvalue-referencetemplate-aliasingstrong-typed enumsdelegating-constructorsconstexpralignmentsinheriting-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

分享到:
评论

相关推荐

    关于__Federico Milano 的电力系统分析工具箱.zip

    1.版本:matlab2014/2019a/2021a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    mlab-upenn 研究小组的心脏模型模拟.zip

    1.版本:matlab2014/2019a/2021a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    混合图像创建大师matlab代码.zip

    1.版本:matlab2014/2019a/2021a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    中序遍历二叉树-java版本

    在Java中,实现二叉树的中序遍历同样可以通过递归来完成。中序遍历的顺序是:首先递归地中序遍历左子树,然后访问根节点,最后递归地中序遍历右子树。 在这段代码中,Node类定义了二叉树的节点,BinaryTree类包含一个指向根节点的指针和inOrder方法,用于递归地进行中序遍历。printInOrder方法调用inOrder方法并打印出遍历的结果。 在Main类中,我们创建了一个示例二叉树,并调用printInOrder方法来输出中序遍历的结果。输出应该是:4 2 5 1 3,这表示中序遍历的顺序是左子树(4),然后是根节点(2),接着是右子树的左子树(5),然后是右子树的根节点(1),最后是右子树的右子树(3)。

    无头单向非循环链表的实现(SList.c)

    无头单向非循环链表的实现(函数定义文件)

    两个有序链表的合并pta

    "PTA" 通常指的是一种在线编程平台,例如“Pata”或者某些特定学校或组织的编程练习与自动评测系统。在这种平台或系统中,学生或程序员会提交代码来解决各种问题,然后系统会自动运行并评测这些代码的正确性。 当提到“两个有序链表的合并PTA”时,这通常意味着在PTA平台上解决一个特定的问题,即合并两个有序链表。具体任务可能是给定两个已按升序排序的链表,要求编写代码来合并这两个链表,形成一个新的有序链表。

    在 Matlab 中创建的图形工具可改善航空航天数据的可视化.zip

    1.版本:matlab2014/2019a/2021a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    搜索引擎的设计与实现.zip

    搜索引擎的设计与实现

    年公司财务会计岗位工作总结(二).docx

    工作总结,新年计划,岗位总结,工作汇报,个人总结,述职报告,范文下载,新年总结,新建计划。

    【基于Springboot+Vue的Java毕业设计】无人超市管理系统项目实战(源码+录像演示+说明).rar

    【基于Springboot+Vue的Java毕业设计】无人超市管理系统项目实战(源码+录像演示+说明).rar 【项目技术】 开发语言:Java 框架:Spingboot+vue 架构:B/S 数据库:mysql 【演示视频-编号:314】 https://pan.quark.cn/s/8dea014f4d36 【实现功能】 无人超市管理系统有管理员,用户两个角色。管理员功能有个人中心,用户管理,商品类型管理,支付类型管理,公告类型管理,商品信息管理,出入库管理,出入库详情管理,购买管理,购买详情管理,公告信息管理。用户可以注册登录,自助购买,点击购买管理里面收银就可以选择支付类型和商品然后提交,还可以查看购买详情和公告信息。

    电视的半盲图像去模糊问题,.zip

    1.版本:matlab2014/2019a/2021a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    公司年会基本流程表.doc

    年会班会资料,节目策划,游戏策划,策划案,策划方案,活动方案,筹办,公司年会,开场白,主持人,策划主题,主持词,小游戏。

    5G智慧港口解决方案.pptx

    在现有省、市港口信息化系统进行有效整合基础上,借鉴新 一代的感知-传输-应用技术体系,实现对码头、船舶、货物、重 大危险源、危险货物装卸过程、航管航运等管理要素的全面感知、 有效传输和按需定制服务,为行政管理人员和相关单位及人员提 供高效的管理辅助,并为公众提供便捷、实时的水运信息服务。 建立信息整合、交换和共享机制,建立健全信息化管理支撑 体系,以及相关标准规范和安全保障体系;按照“绿色循环低碳” 交通的要求,搭建高效、弹性、高可扩展性的基于虚拟技术的信 息基础设施,支撑信息平台低成本运行,实现电子政务建设和服务模式的转变。 实现以感知港口、感知船舶、感知货物为手段,以港航智能 分析、科学决策、高效服务为目的和核心理念,构建“智慧港口”的发展体系。 结合“智慧港口”相关业务工作特点及信息化现状的实际情况,本项目具体建设目标为: 一张图(即GIS 地理信息服务平台) 在建设岸线、港口、港区、码头、泊位等港口主要基础资源图层上,建设GIS 地理信息服务平台,在此基础上依次接入和叠加规划建设、经营、安全、航管等相关业务应用专题数据,并叠 加动态数据,如 AIS/GPS/移动平台数据,逐步建成航运管理处 "一张图"。系统支持扩展框架,方便未来更多应用资源的逐步整合。 现场执法监管系统 基于港口(航管)执法基地建设规划,依托统一的执法区域 管理和数字化监控平台,通过加强对辖区内的监控,结合移动平 台,形成完整的多维路径和信息追踪,真正做到问题能发现、事态能控制、突发问题能解决。 运行监测和辅助决策系统 对区域港口与航运业务日常所需填报及监测的数据经过科 学归纳及分析,采用统一平台,消除重复的填报数据,进行企业 输入和自动录入,并进行系统智能判断,避免填入错误的数据, 输入的数据经过智能组合,自动生成各业务部门所需的数据报 表,包括字段、格式,都可以根据需要进行定制,同时满足扩展 性需要,当有新的业务监测数据表需要产生时,系统将分析新的 需求,将所需字段融合进入日常监测和决策辅助平台的统一平台中,并生成新的所需业务数据监测及决策表。 综合指挥调度系统 建设以港航应急指挥中心为枢纽,以各级管理部门和经营港 口企业为节点,快速调度、信息共享的通信网络,满足应急处置中所需要的信息采集、指挥调度和过程监控等通信保障任务。 设计思路 根据项目的建设目标和“智慧港口”信息化平台的总体框架、 设计思路、建设内容及保障措施,围绕业务协同、信息共享,充 分考虑各航运(港政)管理处内部管理的需求,平台采用“全面 整合、重点补充、突出共享、逐步完善”策略,加强重点区域或 运输通道交通基础设施、运载装备、运行环境的监测监控,完善 运行协调、应急处置通信手段,促进跨区域、跨部门信息共享和业务协同。 以“统筹协调、综合监管”为目标,以提供综合、动态、实 时、准确、实用的安全畅通和应急数据共享为核心,围绕“保畅通、抓安全、促应急"等实际需求来建设智慧港口信息化平台。 系统充分整合和利用航运管理处现有相关信息资源,以地理 信息技术、网络视频技术、互联网技术、移动通信技术、云计算 技术为支撑,结合航运管理处专网与行业数据交换平台,构建航 运管理处与各部门之间智慧、畅通、安全、高效、绿色低碳的智 慧港口信息化平台。 系统充分考虑航运管理处安全法规及安全职责今后的变化 与发展趋势,应用目前主流的、成熟的应用技术,内联外引,优势互补,使系统建设具备良好的开放性、扩展性、可维护性。

    【基于Java+Springboot的毕业设计】线上医院挂号系统(源码+演示视频+说明).rar

    【基于Java+Springboot的毕业设计】线上医院挂号系统(源码+演示视频+说明).rar 【项目技术】 开发语言:Java 框架:Spingboot+vue 架构:B/S 数据库:mysql 【演示视频-编号:300】 https://pan.quark.cn/s/8dea014f4d36 【实现功能】 本次开发的线上医院挂号系统实现了字典管理、论坛管理、会员管理、单页数据管理、医生管理、医生留言管理、医生挂号订单管理、管理员管理等功能。

    年网通营业员个人工作总结.docx

    工作总结,新年计划,岗位总结,工作汇报,个人总结,述职报告,范文下载,新年总结,新建计划。

    财务数据分析模型3.xlsx

    Excel数据看板,Excel办公模板,Excel模板下载,Excel数据统计,数据展示

    最全英语六级真题(从12年到23年总共66个真题)

    最全英语六级真题,从12年到23年总共66个真题。全网最全。

    财务助理实习总结(2).docx

    工作总结,新年计划,岗位总结,工作汇报,个人总结,述职报告,范文下载,新年总结,新建计划。

    基于深度学习的人体姿态识别.zip

    基于深度学习的人体姿态识别.zip

    01. XX塑业有限公司ERP物料编码规则(DOC 6页).doc

    01. XX塑业有限公司ERP物料编码规则(DOC 6页).doc

Global site tag (gtag.js) - Google Analytics