结束语 | 路远,未有穷期

你好,我是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。

课程即将结束,在漫长的学习道路上,它的作用就好像是一个小小的驿站,让你适时停下来休息,补充点食物和清水,为下一次冒险做好准备。希望在你将来的回忆里,还会记得有这么一个给你安心和舒适的地方。

这里我还给你准备了一份毕业问卷,题目不多,希望你能抽出几分钟时间填写一下。我非常愿意听听你对这个课程的反馈和建议,你可以在问卷中畅所欲言。

好了,临别之际,在你上马、踏上新的征途之前,我再送你一句“老话”吧:

一个人写出一个好程序不难,难的是一辈子只写好程序,不写坏程序。

路远,未有穷期,期待我们的下次再会!

精选留言

  • 黄骏

    2020-06-30 10:09:11

    罗老师还在写代码么?
    作者回复

    一直在写啊,不愿意做管理工作,还是代码最实在。

    2020-06-30 11:01:10

  • kenan

    2020-06-30 12:59:56

    罗老师意犹未尽啊!来个升级版,期待不久回归。
    作者回复

    有问题可以随时回来一起讨论。

    2020-06-30 13:20:29

  • 肖亮

    2020-08-06 20:04:07

    罗老师,请教问题,在1个类成员函数里面一个lambda表达式捕获this指针,表达式体里调用类的另一个成员函数,然后把这个lambda表达式赋值给一个全局的函数对象。1.定义1个类对象2.调用成员函数3.把类成员销毁。4. 调用全局函数对象。这个全局函数对象还能调用,且还能使用类的成员变量,是为什么?
    作者回复

    首先要说这种做法是非常危险的,会导致空引用。

    原因我觉得可能是类的实例虽然被销毁了,但它所在的内存还没有被立即覆盖重用,里面的数据都还在,所以lambda去调用的时候还能正常工作。

    但这个就是所谓的“未定义行为”了,表面上看似乎能工作,但实际跑起来就会崩溃。

    2020-08-07 09:02:21

  • 心在飞

    2020-06-30 08:06:55

    感谢罗老师一路相伴,后会有期。
    作者回复

    应该还会有机会。

    2020-06-30 09:10:30

  • sea520

    2020-08-08 17:01:50

    您好!买了你的课程。主要基于boost库。我对boost:asio库老是理解不了,请问有哪些好的方法或建议吗
    作者回复

    学asio库首先要理解proactor模式,处理的是完成事件而不是就绪事件。

    然后要理解它的几个基本概念,比如io_service、strand、end_point,先写同步,再试异步。

    asio的文档很全面,示例代码也很多,可以结合代码文档来学。

    另外现在asio已经支持协程了,用协程来开发会比异步回调好理解的多。

    2020-08-10 09:09:50

  • 种花家

    2020-06-30 09:43:28

    正在学习c++的小白,每次重复听罗老师讲课,就对c++理解和认识有重了一分
    作者回复

    课下再多结合GitHub源码,自己把代码多敲敲,多练习,收获就会更大。

    2020-06-30 09:59:16

  • EncodedStar

    2020-06-30 08:46:05

    有机会,罗老师给我们可以发一些加餐呀,感谢罗老师的这节c++,收获颇多
    作者回复

    加餐需要考虑选题,暂时没想好有哪些内容,欢迎大家留言出主意。

    2020-06-30 09:08:44

  • 十斗簸箕

    2020-07-31 14:26:58

    罗老师,请教个问题,见代码
    #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
    作者回复

    这是把编译期代码和运行期代码弄混了,不能简单地把is_same这样的编译期元函数用在运行期的if-else里,这得要用enable_if才行。

    2020-07-31 15:09:22

  • 肖亮

    2020-07-05 11:32:03

    请教一下罗老师,boost::optional<T&>& a,括号里面的&和外面的&有什么区别,按我的理解应该有外面的&就够了。谢谢
    作者回复

    optional里面存放的是T&类型,然后a又是一个optional&类型。

    这种写法确实有些绕,a是一个变量别名(即引用),它的类型是optional,里面又是一个引用。

    我个人不建议写出这样的代码,难以理解代码的真实意图,有隐患。

    2020-07-05 12:07:12

  • 有学识的兔子

    2020-06-30 08:12:59

    根据老师推荐的书,在网上淘了本 《C++程序设计及演化》 从struct C 到 看到了虚函数的引入,还是有不少收获。
    作者回复

    这本书是很好的,有点哲学的味道。

    2020-06-30 09:10:19

  • 长脖子树

    2022-07-18 13:10:29

    一个工作5年的Java程序员学习完来打个卡 哈哈哈
    作者回复

    great

    2022-07-19 06:57:44

  • Geek_b290e8

    2022-06-17 20:11:29

    希望来个更具体的项目实战课程,这方面内容挺少
    作者回复

    C++的项目一般都很大,不是太好讲,可以先参考一些知名C++开源项目。

    2022-06-20 15:52:00

  • 每天进步一点点

    2021-12-15 14:41:12

    今天把罗老师的课看完了,收获良多。
    作者回复

    many thanks.

    2021-12-15 17:12:44

  • Kevin

    2021-11-02 09:03:08

    老师,强烈建议再来一门更加高级一点的C++实践课程。
    作者回复

    太高级的可能看得人会少啊,模板元编程我自己搁置久了再拾起来都困难。

    2021-11-02 14:37:45

  • bboot9001

    2020-07-04 19:17:31

    感谢罗老师 收获很大
    作者回复

    不客气,欢迎常回来看看。

    2020-07-05 10:03:55

  • 后视镜

    2020-07-03 08:03:59

    刚到了新岗位,以前写了7年的py,开始写c++,学习老师的课程大有收获。
    作者回复

    编程语言都是相通的,相信你用C++也会很出色。

    2020-07-03 08:55:27

  • 青鸟飞鱼

    2020-07-01 16:58:25

    罗老师,可以考虑出出编程范式。也可以加餐来说说老师的经历,哈哈哈。。。
    作者回复

    嗯,会认真考虑的,还要和编辑商量。

    2020-07-02 09:05:12

  • 沉淀的梦想

    2020-07-01 13:32:02

    我平时写的 java,但是对c++一直很感兴趣,感谢老师这么有趣浅显的入门课程
    作者回复

    学了C++,再看java会有不一样的感觉,对自己的工作也会很有帮助。

    2020-07-01 16:26:23

  • Geek_a6104e

    2020-07-01 08:23:55

    感谢罗老师
    作者回复

    不客气,大家一起学习共同进步。

    2020-07-01 08:51:31

  • 木瓜777

    2020-07-01 07:38:48

    期待下一次开课! 罗老师平时主要在哪里了解c++最新特性
    作者回复

    在GitHub里列了一些官方资源,一般去那里看,有时候也会搜一些中文文章来快速了解动向。

    2020-07-01 08:52:27