生命周期和编程范式

  • C++程序的生命周期
  • C++程序的四个阶段
  • C++语言的编程范式
  • C++语言的五种范式
  • 小结

C++程序的生命周期

如果你学过一点软件工程的知识,就一定知道“瀑布模型”,它定义了软件或者是项目的生命周期——从需求分析开始,经过设计、开发、测试等阶段,直到最终交付给用户。

“瀑布模型”把软件的生命周期分成了多个阶段,每个阶段之间分工明确,相互独立,而且有严格的先后次序,是一个经典的开发模型。虽然它已经不再适合瞬息万变的互联网产业了,但仍然有许多值得借鉴和参考的地方。

那么,说了半天,“瀑布模型”跟C++程序有什么关系呢?

其实,从软件工程的视角来看,一个C++程序的生命周期也是“瀑布”形态的,也可以划分出几个明确的阶段,阶段之间顺序衔接,使用类似的方法,就可以更好地理解C++程序的运行机制,帮助我们写出更好的代码。

不过,因为C++程序本身就已经处在“开发”阶段了,所以不会有“需求分析”“设计”这样的写文档过程。所以,一个C++程序从“诞生”到“消亡”,要经历这么几个阶段:编码(Coding)、预处理(Pre-processing)、编译(Compiling)和运行(Running)。

C++程序的四个阶段

编码应该是你很熟悉的一个阶段了,这也是我们“明面”上的开发任务最集中的地方。

在这个阶段,我们的主要工作就是在编辑器里“敲代码”:定义变量,写语句,实现各种数据结构、函数和类。

编码阶段是C++程序生命周期的起点,也是最重要的阶段,是后续阶段的基础,直接决定了C++程序的“生存质量”。

显然,在编码阶段,我们必须要依据一些规范,不能“胡写一气”,最基本的要求是遵循语言规范和设计文档,再高级一点的话,还有代码规范、注释规范、设计模式、编程惯用法,等等。现在市面上绝大部分的资料都是在教授这个阶段的知识,在专栏后面,我也会重点讲一讲我在这方面的一些经验积累。

那么,编码阶段之后是什么呢?

可能对你来说稍微有点陌生,这个阶段叫预处理。

所谓的预处理,其实是相对于下一个阶段“编译”而言的,在编译之前,预先处理一下源代码,既有点像是编码,又有点像是编译,是一个中间阶段。

预处理是C/C++程序独有的阶段,其他编程语言都没有,这也算是C/C++语言的一个特色了。

在这个阶段,发挥作用的是预处理器(Pre-processor)。它的输入是编码阶段产生的源码文件,输出是经过“预处理”的源码文件。“预处理”的目的是文字替换,用到的就是我们熟悉的各种预处理指令,比如#include、#define、#if等,实现“预处理编程”。这部分内容,我后面还会展开讲。

不过,你要注意的是,它们都以符号“#”开头,虽然是C++程序的一部分,但严格来说不属于C++语言的范畴,因为它走的是预处理器。

在预处理之后,C++程序就进入了编译阶段,更准确地说,应该是“编译”和“链接(Linking)”。简单起见,我统一称之为“编译”。

在编译阶段,C++程序——也就是经过预处理的源码——要经过编译器和链接器的“锤炼”,生成可以在计算机上运行的二进制机器码。这里面的讲究是最多的,也是最复杂的,C++编译器要分词、语法解析、生成目标码,并尽可能地去优化。

在编译的过程中,编译器还会根据C++语言规则检查程序的语法、语义是否正确,发现错误就会产生“编译失败”。这就是最基本的C++“静态检查”。

在处理源码时,由于编译器是依据C++语法检查各种类型、函数的定义,所以,在这个阶段,我们就能够以编译器为目标进行编程,有意识地控制编译器的行为。这里有个新名词,叫“模板元编程”。

编译阶段之后,有了可执行文件,C++程序就可以跑起来了,进入运行阶段。这个时候,“静态的程序”被载入内存,由CPU逐条语句执行,就形成了“动态的进程”。

运行阶段也是我们最熟悉的了。在这个阶段,我们常做的是GDB调试、日志追踪、性能分析等,然后收集动态的数据、调整设计思路,再返回编码阶段,重走这个“瀑布模型”,实现“螺旋上升式”的开发。

好了,梳理清楚了C++程序生命周期的四个阶段,你可以看到,这和软件工程里的“瀑布模型”很相似,这些阶段也是职责明确的,前一个阶段的输出作为后一个阶段的输入,而且每个阶段都有自己的工作特点,我们可以有针对性地去做编程开发。

还有,别忘了软件工程里的“蝴蝶效应”“混沌理论”,大概意思是:一个Bug在越早的阶段发现并解决,它的价值就越高;一个Bug在越晚的阶段发现并解决,它的成本就越高。

所以,依据这个生命周期模型,我们应该在“编码”“预处理”“编译”这前面三个阶段多下功夫,消灭Bug,优化代码,尽量不要让Bug在“运行”阶段才暴露出来,也就是所谓的“把问题扼杀在萌芽期”。

C++语言的编程范式

说完了C++程序的生命周期,再来看看C++的编程范式(Paradigm)。

什么是编程范式呢?

关于这个概念,没有特别权威的定义,一个比较通俗的解释:“编程范式”是一种“方法论”,就是指导你编写代码的一些思路、规则、习惯、定式和常用语。

编程范式和编程语言不同,有的范式只能用于少数特定的语言,有的范式却适用于大多数语言;有的语言可能只支持一种范式,有的语言却可能支持多种范式。

那么,你一定知道或者听说过,C++是一种多范式的编程语言。具体来说,现代C++(11/14以后)支持“面向过程”“面向对象”“泛型”“模板元”“函数式”这五种主要的编程范式。

其中,“面向过程”“面向对象”是基础,支撑着后三种范式。我画了一个“五环图”,圆环重叠表示有的语言特性会同时应用于多种范式,可以帮你理解它们的关系。

接下来,我就和你详细说说这五种编程范式。

C++语言的五种范式

面向过程是C++里最基本的一种编程范式。它的核心思想是“命令”,通常就是顺序执行的语句、子程序(函数),把任务分解成若干个步骤去执行,最终达成目标。

面向过程体现在C++中,就是源自它的前身——C语言的那部分,比如变量声明、表达式、分支/循环/跳转语句,等等。

面向对象是C++里另一个基本的编程范式。它的核心思想是“抽象”和“封装”,倡导的是把任务分解成一些高内聚低耦合的对象,这些对象互相通信协作来完成任务。它强调对象之间的关系和接口,而不是完成任务的具体步骤。

在C++里,面向对象范式包括class、public、private、virtual、this等类相关的关键字,还有构造函数、析构函数、友元函数等概念。

泛型编程是自STL(标准模板库)纳入到C++标准以后才逐渐流行起来的新范式,核心思想是“一切皆为类型”,或者说是“参数化类型”“类型擦除”,使用模板而不是继承的方式来复用代码,所以运行效率更高,代码也更简洁。

在C++里,泛型的基础就是template关键字,然后是庞大而复杂的标准库,里面有各种泛型容器和算法,比如vector、map、sort,等等。

与“泛型编程”很类似的是模板元编程,这个词听起来好像很新,其实也有十多年的历史了,不过相对于前三个范式来说,确实“资历浅”。它的核心思想是“类型运算”,操作的数据是编译时可见的“类型”,所以也比较特殊,代码只能由编译器执行,而不能被运行时的CPU执行。

在讲编译阶段的时候提到,模板元编程是一种高级、复杂的技术,C++语言对它的支持也比较少,更多的是以库的方式来使用,比如type_traits、enable_if等。

最后一个函数式,它几乎和“面向过程”一样古老,但却直到近些年才走入主流编程界的视野。所谓的“函数式”并不是C++里写成函数的子程序,而是数学意义上、无副作用的函数,核心思想是“一切皆可调用”,通过一系列连续或者嵌套的函数调用实现对数据的处理。

函数式早在C++98时就有少量的尝试(bind1st/bind2nd等函数对象),但直到C++11引入了Lambda表达式,它才真正获得了可与其他范式并驾齐驱的地位。

这五种编程范式基本覆盖了C++语言和标准库的各个成分,彼此之间虽然有重叠,但在理念、关键字、实现机制、运行阶段等方面的差异还是非常大的。

这就好像是五种秉性不同的“真气”,在C++语言里必须要有相当“浑厚”的内力才能把它们压制、收服、炼化,否则的话,一旦运用不当,就很容易“精神分裂”“走火入魔”。

说得具体一点,就是要认识、理解这些范式的优势和劣势,在程序里适当混用,取长补短才是“王道”。

说到这儿,你肯定很关心,该选择哪种编程范式呢?

拿我自己来说,我的出发点是“尽量让周围的人都能看懂代码”,所以常用的范式是“过程+对象+泛型”,再加上少量的“函数式”,慎用“模板元”。

建议根据自己的实际工作需求来决定。

面向过程和面向对象是最基本的范式,是C++的基础,无论如何都是必须要掌握的,而后三种范式的学习难度就大一些。

如果是开发直接面对用户的普通应用(Application),那么你可以再研究一下“泛型”和“函数式”,就基本可以解决90%的开发问题了;如果是开发面向程序员的库(Library),那么你就有必要深入了解“泛型”和“模板元”,优化库的接口和运行效率。

小结

C++程序的生命周期包括编码、预处理、编译、运行四个阶段,它们都有各自的特点;
虽然我们只写了一个C++程序,但里面的代码可能会运行在不同的阶段,分别由预处理器、编译器和CPU执行;
C++支持面向过程、面向对象、泛型、模板元、函数式共五种主要的编程范式;
在C++里可以“无缝”混用多范式编程,但因为范式的差异比较大,必须小心谨慎,避免导致混乱。

C++ 生命周期和编程范式相关推荐

  1. 变量的作用域和生命周期

    目录 作用域 局部变量的作用域 局部变量的生命周期 生命周期 全局变量的作用域 全局变量的生命周期 作用域 作用域是程序设计概念,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性 ...

  2. Java并发编程:线程的生命周期是个怎样的过程?

    前言 在日常开发过程中,如果我们需要执行一些比较耗时的程序的话,一般来说都是开启一个新线程,把耗时的代码放在线程里,然后开启线程执行.但线程是会耗费系统资源的,如果有多个线程同时运行,互相之间抢占系统 ...

  3. 编程思考:对象生命周期的问题

    前情提要 只要写过 c/c++ 的项目的童鞋应该对对象生命周期的问题记忆犹新.怕有人还不理解这个问题,笔者先介绍下什么是生命周期的问题? 一个 struct 结构体生命周期分为三个步骤: 出生:mal ...

  4. java 关闭守护线程_Java并发编程之线程生命周期、守护线程、优先级、关闭和join、sleep、yield、interrupt...

    Java并发编程中,其中一个难点是对线程生命周期的理解,和多种线程控制方法.线程沟通方法的灵活运用.这些方法和概念之间彼此联系紧密,共同构成了Java并发编程基石之一. Java线程的生命周期 Jav ...

  5. [WCF编程]8.服务实例的生命周期

    一.服务实例的生命周期概览 我们已经直到,通过显式调用Close方法或等待默认的超时时间到来,都可以释放服务实例.但是,在会话连接里,经常需要按一定顺序调用方法. 二.分步操作 会话契约的操作有时隐含 ...

  6. Java并发编程|第二篇:线程生命周期

    文章目录 系列文章 1.线程的状态 2.线程生命周期 3.状态测试代码 4.线程终止 4.1 线程执行完成 4.2 interrupt 5.线程复位 5.1interrupted 5.2抛出异常 6. ...

  7. Vue 生命周期流程(面向对象编程)

    Vue 面向对象编程 面向对象的程序设计实质就是选用一种面向对象程序设计语言(OOPL),采用对象.类及其相关概念所进行的程序设计. 其中面向对象语言是以对象作为基本程序结构单位的程序设计语言,指用于 ...

  8. RXJava2响应式编程框架设计三---Rxjava2背压、生命周期

    在上一次https://www.cnblogs.com/webor2006/p/12348890.html中已经完成了对RxJava2的整个线程切换原理的详细剖析了,这次继续来学习它其它比较重要的知识 ...

  9. java 多线程编程(包括创建线程的三种方式、线程的生命周期、线程的调度策略、线程同步、线程通信、线程池、死锁等)

    1 多线程的基础知识 1.1 单核CPU和多核CPU 单核CPU,其实是一种假的多线程,因为在一个时间单元内,也只能执行一个线程的任务.微观上这些程序是分时的交替运行,只不过是给人的感觉是同时运行,那 ...

最新文章

  1. angular中的class写三元表达式 和 清空表单校验
  2. Azure 执行模型
  3. 【BZOJ】【1038】【ZJOI2008】瞭望塔
  4. 微软全球副总裁给你发了一张Connect 2016专属邀请卡:信仰再充值!Connect 2016技术大会在线直播!
  5. android textview动态设置,android – 如何动态设置文本到TextView?
  6. oracle hibernate 主键,oracle hibernate 主键自增
  7. 墨迹天气语音包_广州天气|冷空气到货,任性吃火锅的理由又有了
  8. Linux 命令(28)—— tee 命令
  9. Python3下载图像小工具
  10. 2021-12-06
  11. 2020年百度之星程序设计大赛-初赛二(Poker、Distance)
  12. 使用EasyDarwin进行rtmp推流
  13. html日期函数,YEAR 函数 (时间日期函数)
  14. caj转成Word文件是怎么转换的
  15. 如何快速使计算机锁屏,电脑如何一键锁屏?有急事时如何快速锁屏?[多图]
  16. Feedback(反馈)
  17. Android热修复——深入剖析AndFix热修复及自己动手实现
  18. 输出菱形图案Python
  19. 如何看计算机cpu的好坏,怎么看电脑的配置(如何判断cpu的好坏)
  20. Python多进程读图提取特征存npy

热门文章

  1. 异常:java.sql.SQLException: 无效的列类型: 1111
  2. 决不应该调用E x i t T h r e a d。应该使用Visual C++运行期库函数_ e n d t h r e a d e x
  3. call与apply
  4. 计算机网络第七部分--因特网协议(英文版本)
  5. 腾讯云iis8.5新建网站无法访问_教程篇 | 使用七牛云存储、CDN加速网站图片
  6. DOS命令 tasklist
  7. Linux下的段错误(Segmentation fault)产生的原因及调试方法
  8. 沉浸式翻译安装使用说明
  9. 机构选股逻辑基因变异 量化投资互联网掘金大数据
  10. 邮箱的格式怎么写,安全邮箱的格式是什么样的?