在31年前(1979年),一名刚得到博士学位的研究员,为了开发一个软件项目发明了一门新编程语言,该研究员名为Bjarne Stroustrup,该门语言则命名为——C with classes,四年后改称为C++。C++是一门通用编程语言,支持多种编程范式,包括过程式、面向对象(object-oriented programming, OP)、泛型(generic programming, GP),后来为泛型而设计的模版,被发现及证实是图灵完备的,所以使C++亦可支持模版元编程范式(template metaprogramming, TMP)。C++继承了C的特点,既为高级语言,又含低级语言功能,可同时做为系统和应用编程语言。php
C++普遍应用在不一样领域,使用者以数百万计。根据近十年的调查,C++的流行程度约稳定排行第3位(于C/Java以后)。 C++经历长期的实践和演化,才成为今日的样貌。1998年,C++标准委员会排除万难,使C++成为ISO标准(俗称C++98),当中含很是强大的标准模版库(standard template library, STL)。以后委员会在2005年提交了有关标准库的第一个技术报告(简称TR1),并为下一个标准C++0x而努力。惋惜C++0x并不能在200x年完成,各界但愿新标准能于2011年内出台。html
流行的C++编译器中,微软Visual C++ 2010已实现部分C++0x语法并加入TR1扩充库,而gcc对C++0x语法和库的支持比VC2010更多。python
C++并不是万能丹,我按经验举出一些C++的适用时机。ios
按应用领域来讲,C++适用于开发服务器软件、桌面应用、游戏、实时系统、高性能计算、嵌入式系统等。程序员
C++和C的设计哲学并不同,二者取舍不一样,因此不一样的程序员和软件项目会有不一样选择,难以一律而论。与C++相比,C具有编译速度快、容易学习、显式描述程序细节、较少更新标准(后二者也可同时视为缺点)等优势。在语言层面上,C++包含绝大部分C语言的功能(例外之一,C++没有C99的变长数组VLA),且提供OOP和GP的特性。但其实用C也可实现OOP思想,亦可利用宏去实现某程度的GP,只不过C++的语法能较简洁、自动地实现OOP/GP。C++的RAII(resource acquisition is initialization,资源获取就是初始化)特性比较独特,C/C#/Java没有相应功能。回顾历史,Stroustrup开发的早期C++编译器Cpre/Cfront是把C++源代码翻译为C,再用C编译器编译的。由此可知,C++编写的程序,都能用等效的C程序代替,但C++在语言层面上提供了OOP/GP语法、更严格的类型检查系统、大量额外的语言特性(如异常、RTTI等),而且C++标准库也较丰富。有时候C++的语法可以使程序更简洁,如运算符重载、隐式转换。但另外一方面,C语言的API一般比C++简洁,能较容易供其余语言程序调用。所以,一些C++库会提供C的API封装,同时也可供C程序调用。相反,有时候也会把C的API封装成C++形式,以支持RAII和其余C++库整合等。正则表达式
相对运行于虚拟机语言(如C#/Java),C/C++直接以静态形式把源程序编译为目标平台的机器码。通常而言,C/C++程序在编译及连接时可进行的优化最丰富,启动时的速度最快,运行时的额外内存开销最少。而C/C++相对动态语言(如Python/Lua)也减小了运行时的动态类型检测。此外,C/C++的运行行为是肯定的,且不会有额外行为(例如C#/Java必然会初始化变量),也不会有如垃圾收集(GC)而形成的不肯定性延迟,并且C/C++的数据结构在内存中的布局也是肯定的。有时C++的一些功能会使程序性能优于C,当中之内联和模版最为突出,这两项功能使C++标准库的sort()一般比C标准库的qsort()快多倍(C可用宏或人手编码去解决此问题)。另外一方面,C/C++能直接映射机器码,之间没有另外一层中间语言,所以能够作底层优化,例如使用内部(intrinsic)函数和嵌入汇编语言。然而,许多C++的性能优势并不是免费午饭,代价包括较长的编译连接时间和较易出错,于是增长开发时间和成本,这点稍后补充。编程
我进行了一个简单全局渲染性能测试(512x512像素,每像素10000个采样),C++ 1小时36分、Java 3小时18分、Python约18天、Ruby约351天。评测方式和其余语言的结果详见博文。数组
C++有不错的跨平台能力,但因为直接映射硬件,因性能优化的关系,跨平台能力不及Java及多数脚本语言。然而,实践跨平台的C++软件仍是可行的,但须注意如下问题:安全
总括而言,跨平台C++软件可在头文件中用宏检测编译器和平台,再用宏、typedef、自定平台相关实现等方法去实践跨平台,C++标准不会提供这类帮助。性能优化
和许多语言相比,C/C++提供不安全的功能以最优化性能,有可能形成崩溃。但要注意,不少运行时错误,如向空指针/引用解引用、数组越界、堆栈溢出等,其余语言也会报错或抛出异常,这些都是程序问题,而不是语言自己的问题。有些意见认为,出现这类运行时错误,应该尽可能写入日志并当即崩溃,不应让程序继续运行,以避免形成更大的影响(例如程序继续把内存中错误的数据覆写文件)。若要容错,可按业务把程序分割为多进程,像Chrome或使用fork()的形式。然而,C++有许多机制能够减小错误,例如以string代替C字符串;以vector或array(TR1)代替原始数组(有些实现可在调试模式检测越界);使用智能指针也能减小一些原始指针的问题。另外,我最常遇到的Bug,就是没有初始化成员变量,有时会致使崩溃,并且调试版和发行版的行为可能不一样。
C++同时提供在堆栈上的自动局部变量,以及从自由存储(free store)分配的对象。对于后者,程序员需手动释放,或使用不一样的容器和智能指针。 C++程序员常常进一步优化内存,自定义内存分配策略以提高效能,例如使用对象池、自定义的单向/双向堆栈区等。虽然C++0x还没加入GC功能,但也能够自行编写或使用现成库。此外,C/C++也能够直接使用操做系统提供的内存相关功能,例如内存映射文件、共享内存等。
我曾参与的C++项目,都会重造很多标准库已提供的功能,此状况在其余语言中较少出现。我试图分析个中缘由。首先,C++标准库相对不少语言来讲是贫乏的,各开发者便会重复地制造自订库。从另外一个角度看,C++标准库是用C++编写的(不少其余语言不用自身而是用C/C++去编写库),在能力和性能上,自订库和标准库并没有本质差异;另外,标准库为通用而设,对不一样平台及多种使用需求做取舍,性能上有所影响,例如EA公司就曾发表自制的EASTL规格,描述游戏开发方面对STL的性能及功能需求的特色;此外,多个C++库一块儿使用,常常会因规范不一样而引发冲突,又或功能重叠,因此项目可能须自行开发,或引入其余库的概念或实现(如Boost/TR1/Loki),改写以符合项目规范。
错,是很是慢。我认为C++多是实用程序语言中编译速度最慢的。此问题涉及C++沿用C的编译连接方式,又加入了复杂的类/泛型声明和内联机制,使编译时间倍增。在C++对编译方法改革以前(如module提案),可以使用如下技巧改善:第一,使用pimpl手法,因性能损耗应用于调用次数很少的类;第二,仅包含必要头文件,并尽可能使用及提供前置声明版本的头文件(如iosfwd);第三采用基于接口的设计,但须注意虚函数调用成本;第四,采用unity build,即把多个cpp文件结合在一个编译单元进行编译;第五,采用分布式生成系统如IncrediBuild。
虽然C++已经很是复杂,但仍缺乏不少常见功能。 C++0x做出了很多改善,例如语言方面加入Lambda函数、闭包、类型推导声明等,而库方面则加入正则表达式、采用哈希表的unordered_set/unordered_map、引用计数智能指针shared_ptr/weak_ptr等。但最值得留意的是C++0x引入多线程的语法和库功能,这是C++演进的一大步。然而,模组、GC、反射机制等功能虽有提案,却未加进C++0x。
我赞成Stroustrup关于使用C++各类技术的回应:“你能够作,不意味着你必须这么作。(Just because you can do it, doesn't mean that you have to.)” C++充满丰富的特性,但同时带来不一样问题,例如过度复杂、编译及运行性能的损耗。通常可考虑是否使用多重继承、异常、RTTI,并调节使用模版及模版元编程的程度。使用过度复杂的设计和功能,可能会令部分团队成员更难理解和维护。
C++的编码自由度很高,容易编写风格迥异的代码,C++自己也没有定义一些标准规范。并且,C++的源文件物理构成,较许多语言复杂。所以,除了决定特性集,每一个团队应创建一套编程规范,包括源文件格式(可以使用文件模版)、花括号风格。
因为C++有对C兼容的包袱,一些功能可使用C风格实现,但最好使用C++提供的新功能。最基本的是尽可能以具名常量、内联函数和泛型取代宏,只把宏用在条件式编译及特殊状况。旧式的C要求局部变量声明在做用域开端,C++则无此限制,应把变量声明尽可能置于邻近其使用的地方,for()的循环变量声明可置于for的括号内。 C++中能增强类型安全的功能应尽可能使用,例如避免“万能”指针void *,而使用个别或泛型类型;用bool而非int表示布尔值;选用4种C++ cast关键字代替简单的强制转换。
如前文所述,C++并不是适合全部应用情境,有时能够混合其余语言使用,包括用C++扩展其余语言,或在C++程序中嵌入脚本语言引擎。对于后者,除了使用各类脚本语言的专门API,还可以使用Boost或SWIG做整合。
C++缺点之一,是相对许多语言复杂,并且难学难精。许多人说学习C语言只需一本K&R《C程序设计语言》便可,但C++书籍倒是多不胜数。我是从C进入C++,皆是靠阅读自学。在此分享一点学习心得。我的认为,学习C++可分为4个层次:
因为我主要是应用C++,大约只停留于第2、三个层次。然而,C++只是软件开发的一环而已,单凭语言并不能应付业务和工程上的问题。建议读者不要强求几年内“完全学会C++的知识”,到达第二层左右便从工做实战中汲取经验,有兴趣才慢慢继续学习更高层次的知识。虽然学习C++有难度,但也是至关有趣且有知足感的。
数十年来,C++虽有起伏,但她依靠其使用者而不断获得顽强的生命力,相信在我退休以前都不会与她分离,也但愿更进一步了解她,与她走进将来。
本文原于《程序员》2010年8月刊揭载。