怎么样才算是精通 C++?
精通C++是一个艰巨的任务。为什么C++比别的语言难学这么多?其实这基本上是因为C++他爹Bjarne Stroustrup说过的一句话“我特别讨厌语言的设计者把自己的喜好强加给用户”(看向go)。结果C++为了不限制你的想法,于是也就变成了现在这个样子--包含若干范式,大概有
面向对象(灵活应用virtual继承+shared_ptr可以达到java/C#的效果)
模板(这里分两类,分别为type rich programming和meta programming,区别很大)
函数式编程(如今有了lambda,配合<algorithm>文件,简直无敌了)
过程式
但是难能可贵的是,这几种东西在C++混在一起用也是多么的自然。不过,这需要你花时间去掌控他。
那到底有没有必要真的学到这个地步呢,我觉得跟你的领域是有关系的。譬如说我,基本上算是人格分裂的,因为:
当我搞语言设计和编译器的时候,我总是会倾向于创造各种小DSL来给自己用,用的都是模板(想想boost的spirit大概就明白我的意思了,虽然我不用它),尽量让跟我有同样背景的人一眼能看懂我代码的意思。
当我做我那个GUI库(www.gaclib.net <https://link.zhihu.com/?target=http%3A//www.gaclib.net>)的时候,纯粹是用OO和IoC那一套。
当我写3D渲染程序的时候,我会变成一个为了性能不惜牺牲可读性的人。
当我是不同的我的时候,我当然只会用C++的一部分来完成我当前的这个任务。这好像是多重标准,但是实际上是由于项目本身的性质而定的。
到了这个时候你会觉得,C++真是一门好语言。当你需要为了你的项目放弃不同的部分的时候,C++都能帮你做到。当你需要不同的抽象层次需要不同的性能要求的是,C++还是能够帮你做到。如果你用别的语言,你最终会发现那个语言只能做某几类的项目。这是因为,C++能够自由的让你放弃某些部分,而别的语言会阻止你放弃某些部分。
为了达到这个层次,你必须进入一个无限接近于精通C++的状态里,这个时候你才能收放自如,不被C++社区的各种不同的价值观所捆绑。倘若你的项目非常大,不同的部分有不同的特征的时候(什么,一个没有遍布全世界的一两千人写了20年的程序能叫程序吗?),就更加需要你有这种本事了。
说到这里,大家大概都明白精通C++大概是个什么感觉了吧--大丈夫能屈能伸。
2
精通没有标准,但学习有路径。 我来说说 学习掌握C++的路径吧,从低到高,分0~10级:
0级:掌握常见C++语法和语言构造,能够顺溜地写清楚各种语言构造(很多小白鼠死在这里)
1级:掌握基本的编程范式:面向过程、面向对象、泛型编程、以及C++11/14支持的函数式编程
2级:清楚编译器在 后面干了什么(compiler under the hood-考验功力的时候到了)
3级:清楚运行时内存模型(memory under the hood)
4级:对经典库(包括但不限于STL, BOOST, Folly)应用熟练,关键原理清晰,掌握设计模式
5级:熟悉至少一个操作系统常用API和内核,调试工具和方法
6级:有清晰的机器和系统模型:CPU, Memery, Cache, GPU, Disk, I/O, Process, Thread, TCP/IP...
7级:有一定系统级应用开发经验,被系统级应用的性能、内存、规模等问题折磨过,并解决过...
8级:从头到尾设计过一个C++库、或框架,并被一定量级的应用使用过
9级:设计并开发过系统级、高性能、大规模的软件系统
10级:成为Bjarne Stroustrup,设计一门语言
当然,这些打怪升级并不完全线性递增,有些需要综合运用。修炼则需要 研习+实践,反复螺旋。
3
实际的面试中,一般按照以下的标准来区分水平。(随便写的,不成系统)
1 听说过C++
常见的问题 什么是类,什么继承
new和malloc有什么区别
什么是虚函数,什么是虚继承
之类的泛泛而谈的入门问题
2 会C++
new实际上执行了什么操作,可能在什么步骤出现异常
怎么写一个class,禁止分配在栈上
怎么突破private的限制访问变量
虚继承的细节
怎么自己模拟实现引用
3 比较了解C++
主要是一些边角的语法或者是不常见的问题
逗号表达式,位域
初始化列表的异常怎么捕获
对于常见的主流编译器,写不写inline有什么影响
完美转发
怎么在编译器判断一个类中有没有定义某个特定的方法
构造函数中调析构函数会有什么结果
4
c艹毕竟只是工具,掌握到可以满足自己设计的需求的程度就够
除非你研究编译,否则对语言本身不必刻意深入。一些边边角角的知识和一些坑,一边做东西一边也就了解了
而是否做出有价值的东西取决于算法水平
精通使用筷子却营养不良,这岂不是更大的笑话…
5
精通就不必强求了,live is too short to program in C++.
学习 C++ 可以经过这么几个阶段。第一是找一本不太「膨胀」的 C++ 教材。基本上掌握 class , overriding, overloading, 最简单的 template (完全不用掌握 partialization )。
第二步是好好阅读《 The Design and Evolution of C++ 》。因为有人说过,一门学科的全部就是它的历史。
接下来你可以学学编译原理,看看高级动态语言,为第四步做准备。
第四步,也就是最最关键的一步。好好看看 C++ FQA (没错,不是 FAQ ,不是 frequently asked question ,而是 frequently questioned answer )。http://yosefk.com/c++fqa/ <https://link.zhihu.com/?target=http%3A//yosefk.com/c%2B%2Bfqa/> 这些揭穿了 C++ 设计者从自身角度文过饰非编写的春秋笔法。《 The Design and Evolution of C++ 》解释了 C++ 为什么是一个怪胎,但是它还是一个怪胎。
6
职业程序员,用了十三四年,依然是小白。
学校的时候,大头书看得头痛,生硬理解概念,现在看来完全不知所以然,但仍经常为自以为懂了一个新特性高兴。那时候还经常为不知什么目的做点练手小程序,当然全是垃圾。
毕业了因为会一些CPP而找到一份不错的工作,坐标海外行业金融,薪水是大多数同班同学的十几倍,那时候个人标签是狂,在大多数人因为难度大而转投JAVA服务器端开发的年代,会点CPP能不狂吗…
工作头两年开始被CPP疯狂的折磨,参与到项目中打下手,全是坑,打印出来几米长的bug单,经常为了查一个崩溃要连续一周每天只睡一小会儿,最后人崩溃。最奇葩的是有人实在受不了,为了通过测试在程序里面设置各种标志位,然后跳槽走人。
工作三四年,逆袭翻身当leader,有了项目话语权,一些设计可以按自己思路走,终于可以施展CPP语法绝学,高级语法,模板满天飞。团队三四个人,干得很好,觉得CPP确实牛逼,效率高,开发方便。团队扩大了,觉得bug怎么冒出来这么多,要找到十个人都精通CPP的语法和特性,真的好难啊,成本好高啊,万一混进来一个猪队友,大家就得通宵陪着加班找bug。
后来老子也辞职不干了,回国创业,发现JAVA真是个好东西,普通学校招一帮子人也能干得风生水起。底层的东西一两个人用CPP搞定,其他能JAVA就JAVA,或者C#。或许这才是最好的模式。
再后来业务领域更专了,要的是结果,至于用什么语言,who在乎。现在更多时候我是在单打独斗,由于习惯原因,加上专业领域的特性,主要还是使用CPP,但我其实想要的是C,无PP,飞一般的编译速度,清晰的结构,灵活的跨二进制接口。
说了这么多,似乎和精通CPP没有什么关系,但现在真的在把CPP当C用,析构函数自动释放资源,太TMD爽了,其他,呵呵。标准库?什么语言没有自己的亲生儿子?STL各个方面都比.NET Framework中对应功能好吗?
再说专业,比如做量化交易,有没有策略和想法,远比会用CPP重要,给个赚钱的idea,只要保证不出乌龙指,程序偶尔崩了,跑慢点又如何 - 场景不同,需求不同。
所以,越简单越好。大部分的人,领域知识比语言工具更重要,我精通不了CPP,所以把使用限制在最基本的层面。
至于OOP,有时候觉得流水账程序嵌套简单的函数调用,比为了OO而OO效果好,除错方便,维护简单。
7
阶段一,C 语言。
这个阶段我并不理解什么是面向过程,只会用 C++ 写一些简单的小函数,掌握了基本的语法。我学生时代基本上就是这个水平。
阶段二,带类的 C 。
这时候我会了简单的面向对象编程,会简单的类的设计与组合,可以写稍微大一些的程序了。我职业生涯的前两年,在创业公司工作的时候,就是这个水平。
阶段三,modern C++ 与规范的编程风格。
这时候我学习了 C++ 11 / 14 / 17 中的新特性,如 lambda expression, std::move, 等等。并且我开始写标准的 unit test,代码风格从混乱到清晰。我在入职某家大厂的前半年多是这个状态。
阶段四,C++ 与其他知识的融合。
这时候我开始把 C++ 与其他的知识贯通了。比如说,从面向对象开始我扩展到了设计模式,从 lambda expression 我开始研究函数式编程,从数组指针等我延伸到了内存管理,等等等等。融会贯通应该精通某一项技能的自然状态。现在的我正在这个阶段的初级阶段。
8
自己心中的精通为何也早有定义:
1) 知道所有关键字的含义,这个是最基本的。有很多很少用的也必须知道……比如auto、mutable、explicit、volatile……通读过一遍 ISO C++标准。
2 )STL的使用和基本实现原理。
3)《Effective C++》、《More Effective C++》……之类的经验手册型书籍熟读3本以上,其中大部分条款要烂熟于胸。
4) boost库的整体框架要了解,清楚其中某些实现的超级BT的库不能被某些编译器编译的原因。还要清楚哪些库将会被iso c++ 收录……用到某些功能的时候会不由自主的想到“boost 中有这个功能?”结果花上比自己手写还要多的时间去使用boost。
4) 看过Moden C++ Design,loki的实现原理要清楚……当然也要知道loki是干什么的……
5) 林锐的《高质量C++编程指南》后面的习题能得到90分以上(记得是第一次做,以后补的不算!)。
6) C++中的线程安全模型是怎样的。
7) C++中的字符串处理库,包括C++对unicode,多种语言编码的支持。
8) 预编译命令都知道是用来干什么的和常见的使用习惯……
9) 平时最常用的一个编译器的所有编译选项熟记于心,以及他和ISO C++定义的编译器的差别。
10)这条凑数……不管怎么样,也要会用gcc……这样保证了在每个平台下面 都可以编译个helloworld按上面的标准查看下自己……还是要继续努力啊……
9
就语言层面来说,正如大部分C程序员都能毫不费力地将任意C源码"肉眼翻译"成伪汇编码那样,一个合格的C++程序员也应当可以做到将任意C++源码"人脑编译"为对应的伪汇编码。但现实的情况是由于C++新增了模板、虚函数、RTTI、虚基类、异常等大量高级特性,以至于能够真正透彻掌握C++语言的程序员不多。
除非完全不使用前文中列出的那些C++高级特性,仅把它作为一个"稍好的C"来使用。否则,对于任何一个职业程序员来说,贸然地使用一种尚不了解其底层(编译器或VM)实现细节的语言特性是一件很危险的事。
关于编译器如何实现异常,可参考小文:C++异常机制的实现方式和开销分析
关于编译器如何实现继承、虚函数、虚基类和 RTTI,可参考小文:RTTI、虚函数和虚基类的实现方式、开销分析及使用指导
至于 Lambda 表达式和闭包这种看起来“神奇”的机制就简单多了,其实只是语法糖而已,可参考小文:C++0x(C++11)新特性点评
对于其它更“一目了然”的语言特性,相信稍有经验的开发者都能不费力地做到“人肉编译”了。
以上仅就C++编程语言方面来讨论。但是需要注意,想成为一个优秀的程序员并是不仅仅精通一门程序设计语言这样简单,还设计数据结构与算法、底层硬件和操作系统等等各种背景知识,以及涉及开发、维护等方面的方法论等各个方面。详见小文《程序员的素质》http://baiy.cn/doc/quality_of_programmer.pdf 。
10
这个问题的确很难讲清楚,可以从这几个方面下手(这是一个死循环体,1->2->3->1):
1、C++的发展历史,包括为什么会出现C++、C++的具体应用、C++的发展前途等,在互联网上好好查查,利用好各大搜索引擎,对C++先要有一定的“感性”(初步)认识;
2、C++的编程思想,包括对象、接口、继承、多态、异常处理、STL、IOstream等编程设计思想,找本厚书,把门窗都关上,使劲的“啃”,理解了的东西才能更好地感觉到它;
3、C++的项目开发(还要学很多其他技术),包括开源项目整改、各种类库开发、外包项目承接等,写个东西,能解决实际问题,并得到使用者的一致好评,正所谓实践验真知。
能做到这三点的,在别人的眼里,都是精通C++的大牛;但他们自己却认为这只是用C++完成个项目而已,接下来还有很多新东西要学。
所以说精通就是要循环地去做这件事,一旦跳出来了,也就成了过去时;“我以前很精通这个的!”你信么?至于你信不信,反正我是不信的!
11
这一阶段需要比较艰辛的过程,需要学习很多书,包括《C++ Programming Language》,《Effective C++》,《More Effective C++》,《Thinking in C++》,《C++对象模型》,《C++ 模版》,如果上述书籍已经很熟悉了,本人认为,在学习阶段,已经很不错了。该过程可以在大学完成,需要一到两年的时间,应为是纯理论的东西,只能算熟悉。在该过程中,需要做一些简单的程序。
12
1 简历上写着了解c++, 实际上不知道mfc 根 VC有什么区别. 0级
2 简历上写着精通c++, 但是仅仅知道mfc, 认为VC就是C++的一切。 1级
3 总是使用malloc,或者 char[100] 来获得内存,但不知道怎么在指定内存上面创建对象。 2级
4 感觉std::string 没有 CString 好用! 听说过g++ 3级
5 会使用std::string, 认为 "c/c++" 很不科学,完全就不是一个语言嘛. 知道4种以上c++ compiler. 感觉自己什么都会。 4级
6 看山是山,看水是水。崇拜boost source code, 呕心沥血的研究经典库的代码. 感觉自己什么都不会。5级
7 看山不是山,看水不是水。为自己钟情的函数库而奋斗着,恨不得用尽各种tricks 和 traits, 因为各种经典设计模式想得头疼. 稍有走火入魔迹象。 6级
8 看山仍然山,看水仍然是水。 看到每行代码,都是汇编的指令和内存数据的移动。 代码中几乎不出现for 和 while 关键字,不停地否定自己的过去。 7级
9 维护着g++,或者Watcom C++ 之类的项目,头发也比较长,有艺术家气质。 8级
10 参与 C++ Standards Committee, 代表不同的利益集团发言。 9级
11 彻底走火入魔, 成天幻想修改C++的语法, 添加自己的关键字, 重新实现一个C++的改进, 还想把c++变成脚本,解释执行。已经超越了利益。 10级.
12
突然想起一个捷径,可以试一试。
C++的每一个特性几乎都不是原创,它有一个来源,你也许可以先去学习一下那个来源。
比如,用C先写一下常见的数据结构,再把它改为ADT范式。
比如,写一个模仿int语义的string类。
比如,面向对象是学smalltalk,可以学习一下smalltalk,再用C++实现一下单继承体系,接口继承,消息传递。还可以抄一个toolkit,实现一下mvc。
比如,学习一下sml,用C++仿写一个基础库。
比如,试试用C++写一个语法描述的DSL,就像bison那样。
比如,还有fp,可以试试翻译一个haskell代码,写成C++。
等等,如果这个列表足够长,应该可以精通C++。
13
会无法忍受 public static void main,想使用类,又想用指针,又想跑的飞快,偶尔还可能插入一段汇编来做些奇怪的事情,喜欢一切都掌握在手里的感觉,优化的时候很痛快,更多地是有理有据有办法地优化,没有垃圾回收在作怪(从这个角度看,这也是一种摧枯拉朽),又想这又想那最后自己成了奇葩。
于是会选择c++这一奇葩,虽然选择了它,但至今都认为这是屎一样的语言,或许永远也无法写的像python有种摧枯拉朽的感觉,但是却可以写的很整齐,每一句都是有理由的,没有一句是不过脑子写出来的,是在雕琢代码。
c++ python js lua 我都喜欢,自己一个人写东西首选py,想掌控一切的时候会考虑c++,可惜自己写自己的东西总是一个人,就我的情况来说还真没有足够的精力,而我又是个极其嫌麻烦的人,真是个遗憾。
14
有对比才有体会吧。我是拿 C++ 和 c# 这个严谨而 OO 程度非常高的语言对比,你可以看到两种语言的设计宗旨的差异和特点:
说点 C++ 的特点:
(1)C++ 里字符和数字无缝衔接,char 和数字(number),是没有任何差异的,你怎样用它把它当什么来用它就是什么。C# 居然不行,非得要 Encoding 来转或者显示 Convert (还不一定是你要的结果),吐血!
(2)switch 语句在 C++ 里可以随意贯穿(落下),c# 不行。你喜欢哪一个?
(3)C++ 引用 dll(静态链接),只要拿来 h,lib,dll 这三个文件,直接 include 就可以用了。C# 要自己写 pinvoke。。累不累啊。
(4)序列化和反序列化,C++ 里可以在内存和文件之间进行直接传输。C# 好像需要手工写,或者要引封送 api,烦!
(5)C++ 可以把类实例声明在栈上(构造也一并完成),非常便捷。C # 必须得写赋值的 new ,(当然这里还有点区别 c# 的内存管理策略也不把对象放在栈上)。
(6)C++ 比 C#(java 也是),少了一个抽象层(平台),也就是说,C++ 写的 windows 程序,不需要装 .net framework 。同时,运行程序的内存需求也远小于后者。换句话说,在硬件比较垃圾的场合,前者的适应性更强。
那么用 C# 的优点是什么呢?
写代码的时候,基本不需要操心什么内存和资源的问题。。。。。。这一条的差异性很大。总之,用 C# 写代码,你会感觉轻松很多,而用 C++ 写代码,真是操碎了心,很累的感觉。