结束语 路远,未有穷期
你好,我是Chrono。
两个月的时间过得好快啊,一眨眼的功夫,就到了和你说“再见”的时候了。
和之前的《透视HTTP协议》一样,我首先要感谢的,还是你——感谢对我和这门课的支持,正是你持续的支持和鼓励,才让我有了创作的激情和动力,Thanks for your support!
同时,我也要祝贺你,祝贺你凭着力量、智慧和勇气(《The Legend of Zelda》的黄金三角),突破了C++的“重重迷雾”,成功地掌握了C++的核心知识和应用技能,相信这将会是你今后工作履历中的一笔“浓墨重彩”。
现在再回头看各节课程,我觉得基本上算是达成了当初预计的目标:贴近实际的开发经验分享,没有剑走偏锋的“葵花宝典”,而是踏踏实实的“太祖长拳”。
但是我觉得这门课程的交付还是有一点点遗憾的。因为C++的内容实在是太丰富了,在课程里,我们只能挑出“必修”的重点和要点来讲,还有很多外围的点没办法展开细讲,还有很多小点来不及说出来,真是舍不得和你说再见。
所以,我想在这最后一讲里,我还能和你交代点啥,我觉得最实际的就是和你聊聊结课后,你该怎么继续学习C++。
课程结束后,你该怎么学C++?
要回答这个问题,我们再来看看这门课的主角C++吧。
从1979年贝尔实验室发明“C with Classes”,到1983年正式命名为“C++”,再到现在,C++已经走过了四十多年,可以说是处于“不惑之年”了。在如今的编程语言界,和Java(1995)、Go(2009)、Rust(2010)等比起来,C++真算得上是“老前辈”。
这么多年来,C++一直没有停止发展的脚步(不过确实有点缓慢),不仅修补了曾经的缺陷,还增加了越来越多的新特性。不可否认,C++虽然变得越来越复杂和庞大,但也正在一步步趋近“完美”,你可以批评它,但绝不能无视它。
个人认为,C++最大的优点是与C兼容,最大的缺点也是与C兼容。
一方面,它是C之外唯一成熟可靠的系统级编程语言(目前Rust还没有达到可以和C++“叫板”的程度),大部分用C的地方都能用C++替代,这就让它拥有了广阔的应用天地。而面向对象、泛型等编程范式,又比C能够更好地组织代码,提高抽象层次,管理复杂的软件项目。比如前段时间刚成功发射的“龙”飞船,它的应用软件就是用C++开发的。
但另一方面,为了保持与C兼容,C++的改革和发展也被“束缚了手脚”,做出任何新设计时,都要考虑是否会对C代码造成潜在的破坏。这就使得很多C++新特性要么是“一拖再拖”,要么是“半成品”,要么是“古里古怪”,最后导致C++变得有些不伦不类,丢掉了编程语言本应该的简洁、纯粹。
如果你看看新出的C++17、C++20,这两方面就表现得特别明显(比如结构化绑定、模块、协程、模板lambda)。也许,这就是C++追求自由和性能的代价吧。
这次的课程里,我们主要用的是C++11/14,那么面对后续的新标准、新特性,在没有“入职导师”的情况下,你要再怎么学呢?
我觉得,对于C++这样复杂的编程语言,你要把握一个基本原则:不要当“语言律师”(language lawyer)。也就是说,不要像孔乙己那样,沉迷于“茴”字有多少种写法,又或者是“抖机灵”式的代码,而是要注重实践、实用。
因为C++的编程范式太多,“摊子”实在是铺得太大,它为了避免各种特性可能导致的歧义和冲突,就会有许许多多细致到“令人发指”的规定,我们在学习的时候,一不小心就会钻进细节里出不来了。
这样的例子有很多,比如说ADL、引用折叠、可变参数模板、“++”的前置和后置用法、模板声明里的typename和class、初始化列表与构造函数、重载函数里的默认参数……
弄懂这些位于“犄角旮旯”里的特性(无贬义),需要花费我们很多的脑力,但在我们一般的开发过程中,通常很少会触及这些点,或者说是会尽力避免,它们通常只是对编译器有意义,所以在这些“细枝末节”上下功夫就不是很值了,说白了,就是性价比太低。
我个人认为,在掌握了专栏里C++11/14知识的基础上,如果再面对一个C++新的语言特性,你不能够在五分钟(或者再略长一点)的时间里理解它的含义和作用,就说明它里面的“坑”很深。
你应当采用“迂回战术”,暂时放弃,不要细究,把精力集中在现有知识的消化和理解上,练好“基本功”,等你以后真正不得不用它的时候,通过实践再来学习会更好。
这也是我自己多年实践的经验,希望对你有用。
结课赠言
结束语的最后,我还是要来一个“首尾呼应”,回顾一下开篇词里的“初心”。
还记得开课时的那三句编程格言吗?
任何人都能写出机器能看懂的代码,但只有优秀的程序员才能写出人能看懂的代码。
有两种写程序的方式:一种是把代码写得非常复杂,以至于“看不出明显的错误”;另一种是把代码写得非常简单,以至于“明显看不出错误”。
“把正确的代码改快速”,要比“把快速的代码改正确”,容易得太多。
这两个月的学习下来,结合C++的各种编程范式、特性和应用经验,你是否对它们又有了一些新的认识呢?
我说说我对这三句格言的理解吧,也许能和你产生共鸣:
- 写代码,是为了给人看,而不是给机器(编译器、CPU)看,也就是human readable;
- 代码简单、易理解最重要,长而复杂的函数、类是不受欢迎的,要经常做Code Clean;
- 功能实现优先,性能优化次之,在没有学会走之前,不要想着跑,也就是Do the right thing。
课程即将结束,在漫长的学习道路上,它的作用就好像是一个小小的驿站,让你适时停下来休息,补充点食物和清水,为下一次冒险做好准备。希望在你将来的回忆里,还会记得有这么一个给你安心和舒适的地方。
这里我还给你准备了一份毕业问卷,题目不多,希望你能抽出几分钟时间填写一下。我非常愿意听听你对这个课程的反馈和建议,你可以在问卷中畅所欲言。
好了,临别之际,在你上马、踏上新的征途之前,我再送你一句“老话”吧:
一个人写出一个好程序不难,难的是一辈子只写好程序,不写坏程序。
路远,未有穷期,期待我们的下次再会!
- 黄骏 👍(24) 💬(2)
罗老师还在写代码么?
2020-06-30 - kenan 👍(5) 💬(1)
罗老师意犹未尽啊!来个升级版,期待不久回归。
2020-06-30 - 肖亮 👍(3) 💬(1)
罗老师,请教问题,在1个类成员函数里面一个lambda表达式捕获this指针,表达式体里调用类的另一个成员函数,然后把这个lambda表达式赋值给一个全局的函数对象。1.定义1个类对象2.调用成员函数3.把类成员销毁。4. 调用全局函数对象。这个全局函数对象还能调用,且还能使用类的成员变量,是为什么?
2020-08-06 - 心在飞 👍(3) 💬(1)
感谢罗老师一路相伴,后会有期。
2020-06-30 - sea520 👍(2) 💬(1)
您好!买了你的课程。主要基于boost库。我对boost:asio库老是理解不了,请问有哪些好的方法或建议吗
2020-08-08 - 种花家 👍(2) 💬(2)
正在学习c++的小白,每次重复听罗老师讲课,就对c++理解和认识有重了一分
2020-06-30 - EncodedStar 👍(2) 💬(4)
有机会,罗老师给我们可以发一些加餐呀,感谢罗老师的这节c++,收获颇多
2020-06-30 - 十斗簸箕 👍(1) 💬(1)
罗老师,请教个问题,见代码 #include <type_traits> class TemplateTest { public: template <typename T> void Test(T &result) { if (std::is_same<T, int>::value) { T = GetInt(); } else if (std::is_same<T, double>::value) { T = GetDouble(); } else if (std::is_same<T, std::string>::value) { T = GetString(); } } private: int GetInt() { return 123; } double GetDouble() { return 123.456; } std::string GetString() { return "string"; } }; void main() { TemplateTest tt; int v1; tt.Test(v1); std::string v2; tt.Test(v2); } 为何我这段代码编译有问题?劳烦指正,编译环境vs2015
2020-07-31 - 肖亮 👍(1) 💬(1)
请教一下罗老师,boost::optional<T&>& a,括号里面的&和外面的&有什么区别,按我的理解应该有外面的&就够了。谢谢
2020-07-05 - 有学识的兔子 👍(1) 💬(1)
根据老师推荐的书,在网上淘了本 《C++程序设计及演化》 从struct C 到 看到了虚函数的引入,还是有不少收获。
2020-06-30 - 长脖子树 👍(0) 💬(1)
一个工作5年的Java程序员学习完来打个卡 哈哈哈
2022-07-18 - Geek_b290e8 👍(0) 💬(1)
希望来个更具体的项目实战课程,这方面内容挺少
2022-06-17 - 每天进步一点点 👍(0) 💬(1)
今天把罗老师的课看完了,收获良多。
2021-12-15 - Kevin 👍(0) 💬(1)
老师,强烈建议再来一门更加高级一点的C++实践课程。
2021-11-02 - bboot9001 👍(0) 💬(1)
感谢罗老师 收获很大
2020-07-04