C++(C plus plus)[2]是一种面向对象的程序设计语言,[10][11]具有泛型编程[10]和与C语言兼容等特点[12],被广泛应用于各个领域的软件开发和系统编程。C++ 是一种高效的编程语言,其提供了指针、引用和内存管理等特性,可以直接操作内存。[10][13]从设计上讲 C++ 在C语言的基础上引入了静态数据成员、类的成员函数,增强了共享性;引入了继承、模板和多态机制以支持重用性。[13]
20世纪80年代初期,美国 AT&T 贝尔实验室的本贾尼·斯特劳斯特卢普(Bjarne Stroupstrup)博士以C语言为基础发明实现了C++,[3]其主要增加了类的设计,增强了C语言的共享能力。[13]1987年,Cfront 2.0 发布,[14]增强了 C++ 的面向对象的程序设计(object oriented programming,OOP) [15]功能,使其 OOP 方法论、设计风格和设计模式等开始流行。[14]1994年,STL 正式成为 C++ 标准库,[16]丰富了 C++ 语言的抽象表达能力,使 C++ 的程序代码变得更加高效易读。[17]1998年8月,ISO 标准被正式通过,[18]意味着 C++ 正式接纳了 STL 和异常处理的加盟以及C++语言的成熟与标准化。[16]到了21世纪,C++ 标准不断变化改进,引入了包括模组和协程等在内的众多新特性,[19]逐渐成为使用最广泛的编程语言之一。[20][21]
C++ 具有丰富的数据类型和运算符,以及结构化的控制语句,能直接访问和控制硬件。[22]C++ 标准库提供了丰富的库函数,以及类、模板等功能,使得程序员的工作更加轻松。[10][23]随着云计算和大数据的兴起,C++ 语言的普及度越来越高。[19]截至2024年5月,在 TIOBE 对编程语言人气的排名中,C++ 排名第3。[21]
C++ 的“面向对象初探与初生阶段”
20世纪70年代初期,为了移植与开发 UNIX 操作系统,美国 AT&T 贝尔实验室的里奇博士(D. M. Ritchie)设计开发了一种通用的、面向过程的计算机程序设计语言,即C语言,其既具有高级语言的特点,又具有汇编语言的特点。因此,C语言可以作为操作系统设计语言,编写系统程序,也可以作为应用程序设计语言,从而编写不依赖计算机硬件的应用程序。[1]
20世纪80年代初期,美国 AT&T 贝尔实验室的本贾尼·斯特劳斯特卢普(D.B.Stroustrup)博士以C语言为基础发明并实现了C++。[3]起初,这种语言被称为带类的C,其主要增加了类的设计,尽管当时还缺少运算符重载、引用和虚函数等,但大大增强了C语言的共享能力,使得程序员能够改进编写程序的质量,并易于程序代码的复用。[13][18]1983年,C++ 名字定下来,并正式向外发布。[24]同时,C语言的大多数内容被保留了下来,很多情况下C语言和C++ 可以互相转化,甚至不用对代码进行任何修改。[1]
1985年10月,第一个 C++ 商业版本发布,该版本是 AT&T 的 Cfront1.0 版本,包括多数最重要、最常用的 OOP 功能,如类、类继承、构造函数和析构函数、new/delete 操作、虚拟函数、内联函数、操作符重载、public 和private 数据保护、友元、关键字等。[4]
1986年,由 D.B.Stroustrup 博士编写的关于C++语言的书籍《The C++ Programming Language》出版。该书以简洁的笔法和简短的案例,影响了一代 C++ 程序员的风格和习惯,是当时真正有影响、有使用价值的书籍之一。[14]
1987年,Cfront2.0 发布。该版本主要增强了 C++ 的 OOP 功能,其主要特征包括多重继承、抽象类、静态成员函数、保护成员、常量成员函数、成员指针。这些功能使 C++ 的 OOP 方法论、设计风格和设计模式等开始流行,C++ 因此真正成为了一门富有哲理性的深邃的程序设计语言。[14]
1990年,玛格丽特·埃利斯(Margaret A. Ellis)和D.B.Stroustrup博士编写[25]的书籍《The Annotated C++ Reference Manual》出版,该书籍是在 C++ 标准化之前,唯一一本能帮助程序员精确理解 C++ 语言构造和语义的书籍。例如,关于 MI 语义层面的描述以及包括内存布局、delta 值的设立等的实现方案,在这本书之前几乎找不到参考文献。[16]
C++ 的“STL与Boost时代”
1994年,[16]由斯捷潘诺夫博士(Alex Stepanov)主持开发[17]的 STL(standard template library,标准模板库)被 ANSI/ISO C++ 委员会接受,正式成为 C++ 标准库。STL 的诞生使 C++ 语言有了自己的基本函数库,丰富了 C++ 语言的抽象表达能力,拓展了 OOP 语言对多态性的理解。[16]STL 里整合了许多常用数据结构和算法模板,使用 C++ 进行程序开发的代码变得更加高效、整洁和易读。[17]
1998年,Boost 社区出现,其由许多 C++ 开发人员群组组成,通过其网站以及几个邮件列表进行协调沟通。Boost 社区开发和发布了 Boost C++ 库。[26]Boost 库是一个可移植、提供源代码的 C++ 库,是C++ 标准化进程的开发引擎之一和程序扩展库的总称。[27]标准模板库(STL)和 Boost 等程序库的出现,使泛型程序设计在 C++ 中占据了越来越多的比重。[28]
C++ 的“复杂性崭露与标准之路”
1998年8月,ISO 标准被正式批准。[18]C++ 正式国际标准(ISO/IEC 14882:1998)的出台,标志着 C++ 语言的成熟与标准化,意味着 C++ 正式接纳了 STL 和异常处理(exceptional handling)的加盟,促进了之后10年 C++ 语言的不断发展。[16]
2007年,C++ TR1(C++技术报告1,TR1)(ISO/IEC TR 19768)公布,受到了C++ 界的广泛关注。TR1 是为了解决 STL 值语义对指针和 REF 的支持不足等问题而提出的改进建议。2011年,C++11 颁布,其正式接受了 TR1,大大改善了 STL 的性能。同时,C++ 语言的语法有了实质性的提升,增加了包括Lambda表达式、并行程序设计(parallel programming)、多线程(multithreading)、value reference 和转移构造函数(move constructor)等 OOP、FP 概念和语言构造。[29]
随着以Loki、MPL等程序库为代表的产生式编程和模板元编程的出现,C++ 通过将新技术和原有技术融合进行创新发展。[30]C++ 标准也在不断演进,其先后发布了包括 C++14、C++17 和 C++20 等多个版本,每个版本都引入了新的功能和改进,进一步丰富了 C++ 的特性集合。[19][31]其中,C++20 标准是近十年来影响最大的一个版本,其新特性包括模组(modules)、协程(coroutines)、视图(view)等,进一步提高了 C++ 的表现力和可维护性。[19]
| 版本 | 发布时间 | 文档名称 | 变化 |
|---|---|---|---|
| C++ 98[33] | 1998年 | ISO/IEC 14882:1998 | 标志着 C++ 语言的成熟与标准化,正式接纳了 STL 和异常处理(exceptional handling)的加盟,[16]增加了转换运算符、mutahle 关键字、RTTI、bool类型等特性[34] |
| C++ 03[35] | 2003年 | ISO/IEC 14882:2003 | 添加了新特性—值初始化[34] |
| C++ 11[36] | 2011年 | ISO/IEC 14882:2011 | 对 C++ 核心语言的运行期进行了强化,使用性能得到了加强,核心语言能力得到了大幅提升,[19]添加了包括 auto 和 decltype、右值引用、列表初始 long long 类型、lambda 表达式、区间遍历等在内的大量新特性[34] |
| C++ 14[37] | 2014年 | ISO/IEC 14882:2014 | 是 C++11 的增量更新,主要支持普通函数的返回类型推演、泛型 lambda、扩展的 lambda 捕获、对 constexpr 函数限制的修订、constexpr 变量模板化等[19] |
| C++ 17[38] | 2017年 | ISO/IEC 14882:2017 | 是继 C++14 之后 C++ 编程语言 ISO/IEC 标准下一次修订的非正式名称[19],添加了折叠表达式、inline 变量、条件语句的初始化器等特性[34] |
| C++ 20[39] | 2020年 | ISO/IEC 14882:2020 | 进一步提高了 C++ 的表现力和可维护性,其新特性众多,包括模组(modules)、协程(coroutines)、视图(view)等[19] |
| 通用名称 | 发布时间 | 文档名称 | 简要说明 |
|---|---|---|---|
| C++ TR1[40] | 2007年 | ISO/IEC TR 19768:2007 | 指定了 C++ 标准库的扩展,拓展包括通用实用程序、 函数式编程、编译时类型查询功能、正则表达式处理等 |
| —— | 2010年 | ISO/IEC TR 29124:2010[41] | 指定了 C++ 标准库的扩展,以支持数学特殊函数 |
| —— | 2011年 | ISO/IEC TR 24733:2011[42] | 指定了 C++ 编程语言的扩展,该扩展提供了与 IEEE 754-2008 规范一致的十进制浮点运算支持 |
| filesystem TS[43] | 2015年 | ISO/IEC TS 18822:2015 | 规定了 C++ 编写的计算机程序用于对文件系统及其组件执行操作的接口的实现要求,适用于能够访问分级文件系统的信息技术系统 |
| parallelism TS[44] | 2015年 | ISO/IEC TS 19570:2015 | 描述了 C++ 编写的计算机程序调用并行执行算法的接口的实现要求,算法可在广泛的计算机体系结构中实现,可用于并行计算 |
| TM TS[45] | 2015年 | ISO/IEC TS 19841:2015 | 描述了 C++ 编程语言的扩展,使事务性内存规范成为可能,扩展包括新的语法形式和对现有语言和库的修改 |
| concepts TS[46] | 2015年 | ISO/IEC TS 19217:2015 | 描述了对 C++ 编程语言的扩展,允许规范和检查模板参数的约束,以及基于这些约束重载函数和专门化类模板的能力,扩展包括新的语法形式和对现有语言语义的修改 |
| concurrency TS[47] | 2016年 | ISO/IEC TS 19571:2016 | 描述了用于并发计算的扩展,该扩展是实验性的,不是 C++ 标准库的一部分 |
| library fundamentals TS[48] | 2017年 | ISO/IEC TS 19568:2017 | 描述了 C++ 标准库的扩展,扩展包括可能在程序和/或不同组织编写的库之间的接口边界上广泛使用的类和函数 |
| ranges TS[49] | 2017年 | ISO/IEC TS 21425:2017 | 描述了 C++ 编程语言的扩展,允许对数据范围进行操作,扩展包括对现有库功能的更改和添加,以及对一个核心语言功能的扩展 |
| coroutines TS[50] | 2017年 | ISO/IEC TS 22277:2017 | 描述了 C++ 编程语言的扩展,可以定义协同程序,扩展包括新的语法形式和对现有语言语义的修改 |
| networking TS[51] | 2018年 | ISO/IEC TS 19216:2018 | 描述了 C++ 标准库的扩展,规定了以 C++ 编写的计算机程序可用于执行与网络相关的操作,以及接口的实现要求,适用于能够执行网络操作的信息技术系统 |
| parallelism TS[52] | 2018年 | ISO/IEC TS 19570:2018 | 描述了接口的实现要求,用 C++ 编程语言编写的计算机程序可以使用该接口来调用并行执行的算法 |
| modules TS[53] | 2018年 | ISO/IEC TS 21544:2018 | 引入了模块,通过符号名称指定一组翻译单元的功能,表达对模块的符号依赖性的能力以及定义模块的接口 |
设计原则
C++ 通过使用静态类型系统、支持堆栈变量和全局变量、支持过程的内联(inline)、使用类型清除(type erasure)从而使 OOP 在 runtime 保持轻量化以及基于各种平台的优化等手段来保证 runtime 效率。[54]C++ 中所有语言构造必须“高效”地实现,且有满意的实现语义。一些不需要的语言构造可以选择性地关闭,从而避免应用为一些不需要的语言特征买单。同时,语言构造要足够简单,使用户无需太多的学习时间就可以掌握,从而吸引更多的使用者。[54]C++ 自始至终定义为一个静态类型系统,拒绝动态程序设计的理念。[54]
主要特点
面向对象:C++ 支持面向对象编程,可以使用类和对象来组织代码,并且支持封装、数据隐藏、继承和多态等面向对象的概念。[11]泛型编程:C++ 可以通过模板实现泛型编程。C++ 在C语言的基础上增加了类、模板等功能,在使用 C++ 进行程序设计的时候,只需要考虑如何将程序中的物件抽象为类,并且定义类之间的关系和互动,不需要考虑函数参数或者容器元素的类型。[10]
高效性:C++ 是一种高效的编程语言,可以直接操作内存,并且具有低级别的控制能力。它提供了指针、引用和内存管理等特性,可以实现底层的算法和数据结构。[10][13]
共享性和重用性:C++ 在C语言的基础上引入了静态数据成员和类的成员函数,增强了共享能力,同时引入了继承、模板和多态机制,从而支持重用性和灵活性。[13]
可移植性:C++ 可以在不同的平台上编译和运行,具有良好的可移植性。[55]它的标准库提供了大量的函数和类,可以方便地进行文件操作、字符串处理、数学运算等常见任务。 [23]
强大的工具支持:C++ 拥有丰富的开发工具和库,如编译器[56]、调试器、集成开发环境等,可以帮助开发者提高开发效率和代码质量。 [9]与C语言兼容:C++ 是以C语言基础发明的,很多情况下C语言和 C++ 可以互相转化。[1]因此,C++ 全面兼容C语言,绝大多数C程序可以在 C++ 中直接运行。[12]
C++工作原理
C++ 程序从编写到最后得到运行结果的过程称为程序开发过程,具体流程如下图所示:[57]

编写源程序:用高级语言编写的程序称为“源程序(source program)”,源程序编写完后,以文本形式保存到磁盘中,经过编辑后得到的源程序文件以“.cpp”做为源程序文件扩展名。[57]编译源程序:为了使计算机能执行高级语言源程序,必须先调用“编译器(complier)”,也称编译程序或编译系统,将源程序编译成二进制形式的“目标程序(object program)”。同时,系统还会对源程序的语法进行检查,当发现错误时,会在屏幕上列出错误的位置和种类。如果源程序没有语法错误,经过编译后的程序文件以“.obj”为目标程序的拓展名。[57]链接目标代码:编译后产生的目标程序还不能直接运行,因为每一个模块往往都是单独编译的,需要把各模块编译后得到的目标程序与系统提供的标准库函数等链接后才能运行,链接过程是使用系统提供的“链接程序”进行的。[57]在链接的过程中,链接程序会自动检查各个程序之间存在的链接错误。如果出现错误,则会出现错误提示信息,报告出错的位置。用户可根据提示信息,修改错误并重新链接。[58]如果没有错误,则会产生以“.exe”为扩展名的可执行程序。[59]运行程序:可执行文件是一个可以运行的程序。在命令行界面下输入可执行文件名就可以运行该程序。[59]若执行结果达到预期的目的,则开发工作到此完成。否则,要进一步检查修改源程序,再经过“编辑→编译→链接”的过程,直到取得正确的运行结果为止。[57]分析运行结果:如果运行结果不正确,应检查程序或算法是否有问题。[57]程序调试:当程序中存在一些逻辑错误时,程序运行结果通常可能是不正确的或异常终止。例如,算法设计有问题或有些特殊情况没有考虑。程序员称这种错误为bug。找出并改正这种逻辑错误的过程称为调试(debug),其一般需要不断运行程序,通过观察程序的阶段性结果来找出错误的位置和原因。[59]结束程序:当程序取得正确的运行结果时,程序结束。[57]
常量和变量
编写程序时已经确定的值,称为常量;尚不确定的值,称为变量。[60]
常量:常量是指在程序运行的过程中,其值不能被改变的量,在程序中可以直接使用,分为普通常量和符号常量。常量可以是不同类型的数据,如:123、-6、9为整型常量;5.14、0.635为实型常量;a、B为字符常量。[61]
变量:从程序员角度,变量定义说明了程序中尚未确定的值、值的类型以及其可以被执行的操作。从计算机的角度来看,变量定义为未确定的值准备好存储空间,使这些值被确定时有一个地方保存它们。变量的类型决定为每个变量准备多少空间。在 C++ 中,变量定义格式和示例如下:[60]
类型名 变量名1,变量名2,...,变量名n;
int num1,num2; //定义了两个整型变量num1和num2 double area; //定义了一个实型变量
在定义变量时,需要注意变量名必须以字母或下划线开头,且其他字符必须是字母、数字或下划线,不得使用空格和其他特殊符号;不可以是系统的保留字,如int、double、for、return等;在C++语言中,变量名是区分大小写的,例如,ABC、Abc和abc是3个不同的变量名。[60]
标识符
标识符是由程序员定义的记号,[62]用来对 C++程序中的符号常量、变量、用户自定义函数、函数的参数、语句标号结构和类以及其他对象的名称进行标识的符号。在C++语言中,标识符需要遵循的命名规则如下:[63]
标识符是以字母(A~Z或a~z)或下划线(_)开头,其他部分由字母、下划线数字(0~9)组成的字符串,不允许出现如@、&和%等特殊字符。例如,1book、a&b、%test均为非法标识符;[63]标识符中的字母区分大小写,例如,test和Test是两个不同的标识符;[63]标识符的名字中间不能有空格;[63]标识符不能与关键字重名。例如:关键字long、short 和int 均不能作为标识符;[63]标识符不能与C++的库函数名、类名和对象名相同;[63]标识符应当直观易读,例如:bookname;[63]标识符中字符个数不宜过多,尽量少于32个字符,保证其可读性;[63]代码中尽量不要出现仅靠大小写区分的标识符。[63]
关键字
关键字是组成编程语言词汇表的标识符,是C++的核心,不能用于其他用途。[62][64]例如,变量名是一种标识符,在程序中,只要不使用C++预定义的关键字,就可以随意选择变量名。[62]
| 类型 | 关键字 |
|---|---|
| 数据类型说明符和修饰符 | bool、char、class、const、double、enum、float、int、long、short、signed、struct、union、unsigned、void、volatile |
| 存储类型说明符 | auto、extern、inline、register、static |
| 访问说明符 | friend、private、protected、public |
| 语句 | break、case、catch、continue、default、do、else、finally、for、goto、if、return、switch、throw、try、while |
| 运算符和常量 | delete、false、new、sizeof、true |
| 其他 | asm、explicit、namespace、operator、template、this、typedef、typename、using、virtual |
数据类型
数据类型描述了数据实体的特性,包括值、内存空间大小等信息。每个类型实体所占的内存空间大小是不同的,对应的取值范围也不同。[66]
布尔型:C++ 定义了一种被称为布尔(Boolean)的类型,该名称以法国数学家George Bool命名,在程序中实际使用的类型说明符为 bool,是一个关键字,用于表示两个值的比较结果,结果要么是真(true),要么是假(false)。例如,如果比较整数23和24是否相等,结果为false。[67]整型:没有小数部分的数值称为整数。例如,数值1376是一个整数,数值1376.25不是一个整数。C++ 允许 short int、int、long int 三种不同大小的整数。这三种不同类型的整数都可以是有符号的或者无符号的,即 C++ 实际上定义了六种不同的整数类型。[67]字符型:字符型数据包括计算机所用编码字符集中的所有字符,类型说明符为 char。字符型的数据在内存中存储的是其 ASCII 码值。常用的 ASCII 字符集包括所有大小写英文字母、数字、各种标点符号字符以及控制字符共128个。扩展的 ASCII 字符集包括常用的 ASCII 字符集中的128个字符在内,共256个字符。[68]
浮点型:在C++ 中,带小数部分的数值被称为浮点类型。为了提高计算效率,C++ 定义了包括 float、double 和 long double 三种不同的浮点大小,所有浮点数都是有符号数。在计算机中,浮点数使用IEEE标准进行存储。[67]
空类型:空类型是没有值的特殊类型,类型说明符为 void,用于显示出缺少值的情况。例如,可以使用 void 来表示一个函数不返回任何值。[67]
构造类型:构造类型是根据已定义的一个或多个基本类型构造的方法来定义的,也就是说,一个构造类型的值可以分解成若干成员或元素,每个成员都是一个基本类型或有一个构造类型。构造类型主要有数组、结构体、联合体等。[68]枚举:枚举型在C++中用于声明一组命名的常数,类型说明符为enum,当一个变量有几种可能的取值时,可以将它定义为枚举型类型。枚举常量代表该枚举型的变量可能取的值,各枚举常量的值可以重复。枚举型的用处之一是用来描述状态量,增加程序的可读性。[68]
字符串类:C++ 定义了一种新的字符串类,是用户自定类型,类型说明符为 string。在 C++ 库中定义了 string 类,要使用 C++ 字符串,必须在程序中包含头文件<string>,即 #include <string>。[67]
| 分类 | 数据类型 | 说明 | 字节 | 取值范围 | ||
|---|---|---|---|---|---|---|
| 基本数据类型 | bool | 布尔型 | 1 | false(0)和 true(1) | ||
| int | unsigned int | 无符号整型 | 4 | 0 ~ 232-1 | ||
| signed int | 有符号整型 | 4 | -231 ~ 231-1 | |||
| short(int) | unsigned short(int) | 无符号短整型 | 2 | 0 ~ 65535 | ||
| signed short(int) | 有符号短整型 | 2 | -32768 ~ 32767 | |||
| long(int) | unsigned long(int) | 无符号长整型 | 4 | 0 ~ 231-1 | ||
| signed long(int) | 有符号长整型 | 4 | -231~ 231-1 | |||
| char | unsigned | 无符号字符型 | 1 | 0 ~ 255 | ||
| signed | 有符号字符型 | 1 | -128 ~ 127 | |||
| float | 浮点型 | 4 | -3.4E-38 ~ 3.4E+38 | |||
| double | 双精度浮点型 | 8 | -1.7E-308 ~ 1.7E+308 | |||
| void | 空类型 | |||||
| 构造数据类型 | array | 数组 | ||||
| struct | 结构体 | |||||
| union | 联合体 | |||||
| 用户自定义数据类型 | enum | 枚举 | ||||
| string | 字符串类 | |||||
运算符
运算符是指对常量或变量进行运算及处理的符号,也是构成表达式的重要元素。C++中具有极其丰富的运算符,这些运算符又具有不同的优先级和结合性,使得C++能够进行各种复杂的数学、工程等运算。[69]
| 类型 | 符号表示 | 描述 | |
|---|---|---|---|
| 算术运算符 | (加)、(减)、(乘)、(除)、(取余) | 加、减、乘、除和模运算分别用于执行两个数的相加、相减、相乘、相除和取余操作 | |
| (自增)、(自减) | 分别为对一个数进行加1、减1操作 | ||
| 关系运算符 | (大于)、(大于等于)、(小于)、(小于等于)、(等于)、(不等于) | 用于对两个数的大小进行比较判断 | |
| 逻辑运算符 | (与)、(或)、(非) | 分别用于进行逻辑与、或、非操作 | |
| 位运算符 | (位与)、(位或)、(位非)、(位异或)、(左移)、(右移) | 分别用于进行位与、位或、位非、位异或、左移和右移操作 | |
| 赋值运算符 | 简单赋值 | 将右侧操作数的值赋给左侧左侧操作数 | |
| 复合算术赋值 | 运算符左侧的数值与右侧的数值进行相加、相减、相乘、相除和取余后,将结果重新赋予左侧操作数 | ||
| 复合位运算赋值 | 运算符左侧的变量与右侧的变量进行位与、位或、位异或、左移和右移操作,将结果重新赋予左侧操作数 | ||
| 长度运算符 | sizeof() | 用于计算存储某种数据类型或变量所需的字节数。表达式为:sizeof(<数据类型>)或sizeof(<变量名>) | |
| 作用域解析运算符[70] | 用于解决名字的冲突。例如,当存在一个全局变量 vector_location 时,一个函数要对变量 vector_location 用一个局部说明,则限定符 ::vector_location 允许在这个局部函数中访问这个全局变量 | ||
| 成员访问运算符[71] | 、 | 用于访问一个对象的某个成员。表达形式分别为:结构变量名.成员名;指向结构的指针->成员名 | |
| 成员指针访问运算符[72] | 、 | 用于访问一个数据成员指针所指向的内容。通过类对象进行访问:<类对象> .* <数据成员指针>;通过指向类对象的指针进行访问:<类对象> ->* <数据成员指针> | |
| 三元运算符(条件运算符)[73] | 用于实现简单的判断功能。表达式为:表达式1 ? 表达式2 : 表达式3;若表达式1的值非零或为true,则整个条件表达式的值为表达式2的值;反之,则整个条件表达式的值为表达式3的值 | ||
语法结构
程序中的基本控制结构顺序结构、选择结构和循环结构三种。C++ 中提供了这三种结构的控制语句。语句是 C++ 程序中最小的可执行单元,一条语句由一个分号结束。[74]
顺序结构
所谓顺序结构,就是指按照语句在程序中的先后次序一条一条的顺序执行。顺序控制语句是一类简单的语句,包括表达式语句、复合语句、空语句和输入/输出语句等。[74]
表达式语句是任何一个表达式加上一个分号,示例如下:[74]
//表达式语句示例 a=1+n*2; x=3,y=10,c=1; a>b? a++ : b++;
复合语句就是用一对花括号{ }括起来的语句序列,也称为块。示例如下:[74]
//复合语句示例 { int x,y; //在一个复合语句中可以定义变量 x=2; y=5*x*x-3*x+8; }
空语句是指只有一个分号“;”的语句,其不做任何操作,用在需要一条语句,但又不做任何操作的地方。输入/输出语句用于实现程序的人机交互功能,通常从键盘输入数据,从显示器输出结果。[74]
选择结构
C++ 中的选择控制语句有if语句、if...else 语句、if...else if 语句和 switch 语句。[75]
if 语句
if 语句用于在程序中有条件地执行某一语句序列,其基本语法格式和程序示例如下:[75]
//基本语法格式 if(条件表达式) 语句; //当“条件表达式”为真时执行后面的“语句”,其中“语句”既可以是单个语句,也可以是复合语句
//程序示例:编写一个程序,显示用户输入数值的绝对值 #include <iostream.h> void main() { int x; cout<<"x=";cin>>x; if(x<0) x=-x; cout<<x<<endl; }
if...else 语句
在“条件表达式”为真和为假时分别执行不同的语句,用 else 来引入条件表达式为假时执行的语句序列。其基本语法格式和程序示例如下:[75]
//基本语法格式 if(条件表达式) 语句1; else 语句2; //当“条件表达式”为真时执行“语句1”;当“条件表达式”为假时执行语句2,这些语句均可以是复合语句
//程序示例:显示用户输入数值的绝对值 int x,y; if(x<0) y=- x; else y=x;
另外,简单的 if..else 语句,可以使用条件运算符来代替。条件运算符是具有三个操作数的三目运算符,由“?”和“:”组成,其一般语句格式和示例如下:[75]
//语句格式 表达式1? 表达式2:表达式3 //先计算“表达式1”的值,若为真,则计算“表达式2”的值并作为整个条件表达式的值; //若“表达式1”的值为假,则“计算表达式3”的值并作为整个条件表达式的值
//语句实现:显示用户输入数值的绝对值 y=(x<0)? -x: x;
if...else if 语句
if...else if 语句用于进行多重判断,其基本语法格式和程序示例如下:[75]
//基本语法格式 if(条件表达式) 语句1; else if(条件表达式1) 语句2; ... else if(条件表达式n) 语句n; else 语句n+1;
该功能语句执行顺序为:先计算“条件表达式1”给出的表达式值,如果该值为真,则执行“语句1”,执行完毕后转到该条件语句后面继续执行其后的语句;如果该值为假,则继续计算“条件表达式2”给出的表达式值。如果“条件表达式2”的值为真,则执行“语句2”。依此类推,如果所有条件中给出的表达式值都为假,则执行 else 后面的“语句n+1”。如果没有 else,则什么也不做,转到该条件语句后面的语句继续执行。[75]
//程序示例:将用户输入的分数转换成等级:A(≥90),B(80~89)C(70~79)D(60~69),E(<60) float x; cout<<"分数:";cin>>x; if(x>=90) cout<<"A"<<endl; else if(x>=80) cout<<"B"<<endl; else if(x>=70) cout<<"C"<<endl; else if(x>=60) cout<<"D"<<endl; else cout<<"E"<<endl;
switch 语句
switch 语句也称为开关语句,用于有多重选择的场合,测试某一个变量具有多个值时所执行的动作,其基本语法格式和程序示例如下:[76]
//基本语法格式 switch(整型表达式) { case 整型常量表达式1:语句1; case 整型常量表达式2:语句2; ... case 整型常量表达式n:语句n; default: 语句n+1; }
该功能语句的执行顺序为:先计算 switch 语句中“整型表达式”的值,然后在 case 语句中寻找值相等的整型常量表达式,并以此为入口标号,开始顺序执行。如果没有找到相等的整型常量表达式,则从“default:”开始执行。[76]
//程序示例:输入课程显示相应的学分:数学(代号为m,8学分)、语文(代号为w,8学分)、英语(代号为e,6学分) char ch; cout<<"课程代号:";cin>>ch; switch (ch) { case 'm': case 'M': case 'w': case 'W': cout<<"8学分"<<endl; break; case 'e': case 'E': cout<<"6学分"<<endl; break ; default; cout<<"输入的课程代号不正确"<<endl; }
循环结构
循环控制语句提供重复处理的能力,当某一特定条件为真时,循环语句就重复执行,并且每循环一次,就会测试一下循环条件,如果为假,则循环结束,否则继续循环。C++ 支持 while、do while 和 for 三种格式的循环控制语句。[77]
while 语句
while 循环,也称为前置条件循环或当型循环。[78]其基本语法格式和程序示例如下:[77]
//基本语法格式 while(条件表达式) 语句; //表达式可以是任意合法的表达式,是循环的控制条件 //语句是循环执行的循环体,可以是C++的任意一条语句
该控制语句的执行顺序为:当“条件表达式”的运算结果为真时,则重复执行“语句”。每执行一次“语句”后,就会重新计算一次“条件表达式”;当该表达式的值为假时,循环结束。[77]
//程序示例:将用户输入的整数反向显示出来 int digit,num; cout<<"输入一个整数:";cin>>num; while(num!=0) //依次求个位、十位...上的数字 { digit=num%10; num=num/10; cout<<digit; }
do while 语句
do while 循环和 while 循环相似,只不过循环的控制条件测试放在了循环体的后面,称为后置循环,或直到型循环。do while 循环保证了循环体语句至少执行一次,[78]其基本语法格式:[77]
//基本语法格式 do 语句; while(条件表达式);
该控制语句的执行顺序为:先执行循环体语句,后判断循环条件表达式的值。表达式的值为真,继续执行循环,表达式的值为假,则结束循环。[78]程序示例如下:[77]
//程序示例:将用户输入的整数反向显示出来 int digit,num; cout<<"输入一个整数:";cin>>num; do { digit=num%10; num=num/10; cout<<digit; }while(num!=0) ;
for 语句
for 循环的使用最为灵活,既可以用于循环次数已知的情况,也可以用于循环次数未知的情况。[78]其基本语法格式和程序示例如下:[77]
//基本语法格式 for(初始化语句;表达式1;表达式2)语句; //初始化语句为循环初值表达式,表达式1为控制表达式(循环终值表达式),表达式2为增量表达式 //语句序列为任意合法的C++语句或复合语句
该控制语句的执行顺序为:先执行“初始化语句”,再计算“表达式1”的值,如果“表达式1”的值为真,则先后执行后面的“语句”和“表达式2”,然后继续计算“表达式1”;如果“表达式1”的值为假,则结束循环。[77]
//程序示例:将用户输入的整数反向显示出来 int digit,num; cout<<"输入一个整数:";cin>>num; for(digit=num%10;num!=0;num=num/10,digit=num%10) cout<<digit; cout<<endl;
跳转结构
C++ 中有 break、continue、goto和return 4种无条件跳转语句。其中,break 和 continue 可用于循环语句中,break 亦可用于 switch 语句中;return 语句用于实现函数返回。[79]
break 语句
break 语句可用于switch 和循环语句中,分别有以下两种用途:[79]
在 switch 中终止某个 case 子句,并跳出 switch 语句。[79]立即结束当前所在层的循环,使程序从循环语句后面的第一个语句继续执行。[79]
break 语句的格式[80]和程序示例[79]如下:
break; //终止当前操作
//用break语句计算1+2+…+10 int sum=0,num=l; while(num <=100}{ sum+=num; if(num==10) break; //break使程序从循环中立即退出,并转到后续语句执行, num++; }
continue 语句
continue 与break 不同的是,continue 语句是使程序跳过本次循环的剩余语句,并回到循环的条件测试部分,重新开始执行循环,而不是立即终止所在循环。[79]
continue 语句的格式[80]和程序示例[79]如下:
continue; //跳过后续语句,重新开始循环
//累加1~100所有能整除10的整数的和 int sum=0,num=0; while(num <=100}{ num++; if(num%10!=0) continue; //跳过本次循环的剩余语句并转到循环的开头 sum+=num; //只有当num整除10时,才执行累加求和操作 }
goto 语句
goto 语句要求有一个标号,后面跟有冒号的有效标识符。标号必须与使用它的 goto 语句在同一函数中,即不能在不同函数之间跳转。goto 语句的一般形式和示例如下:[79]
goto label; label : //label为标号,既可以放在goto语句的前面,也可以放在goto语句的后面
i=1;sum=0; loopLable: //标号的命名遵循标识符的命名规则 sum+=i++; if(i<=100) goto loopLable; //goto语句是的程序从多重循环内部直接跳转到循环之外
return 语句
return 语句用来明确地从一个函数中返回,因为其可使程序返回到调用函数的地方继续执行,所以C++将它归入跳转结构。return 带回的数值即为函数的返回值。[79]
其他相关语句
一个 C++ 程序是由一系列语句组成的。C++ 提供了许多不同类型的语句,每条语句都有一个预定义的任务。[81]
声明语句
声明:通过指定实体的类型并给它一个名称(标识符)来引入一个实体。[81]定义:表示为实体分配内存。[81]
变量的声明:单个变量的声明为一个变量命名并定义其类型,其在内存中保留一个物理位置,保存所声明类型的数据项;同一类型的多个变量的声明可以进行组合并只使用一个声明语句。代码示例如下:[81]
//单个变量的声明 short test; int sum=0; //声明变量时可进行初始化 double average; //多个变量的声明 int first,second,third; //需要用逗号分隔变量名
常量的声明:常量是一个内存位置,其值通过初始化设定且不能被更改。常量声明需注意:在类型前面需要使用关键字 const;必须在声明常量时对其进行初始化;习惯上使用大写字母命名常量,名称涉及多个单词时,使用下划线分隔;常量通常在程序的全局区域中声明,以使常量在所有函数中都可见。代码示例如下:[81]
//常量的声明 const int FOOT_TO_INCH=12; const double PI=3.1415926;
表达式语句
表达式语句是以英文分号结尾(作为结束符)的表达式。表达式有一个值,且可能还有副作用[注1]。当在程序中出现表达式语句时,计算机确定其值并执行其副作用,从而改变计算机的内存状态。没有副作用的表达式作为语句是无用的。[83]
num=10; //表达式语句 num*=10; //表达式语句 num1+num2; //没有作用 num; //没有作用
空语句
空语句是不执行任何操作的语句,一般用于 C++ 语法需要语句但不需要副作用的场合。代码示例如下:[83]
num=24; //包括一条表达式语句和一条空语句
复合语句
在一对花括号内组合任意数量的语句,将其视为单条语句,即为复合语句,也称为语句块,一般用于 C++ 语法需要单条语句但实际需要多条语句时。代码示例如下:[83]
{ int num=8; cout<<num<<endl; }
标准库
C++ 标准库(standard library)提供了丰富的函数集合,可以进行常用的数学计算、字符串操作、字符操作、输入/输出、错误检查和许多其他操作。这些函数提供了许多程序员需要的功能,使得程序员的工作更加轻松。C++ 标准库函数是在C++编程环境中提供的。[23]
函数
C++ 中的模块称为函数(function)和类(class)。其中函数可分为程序员定义函数[注2](programmer-defined function)和C++标准库中的预装函数。C++程序一般由程序员定义函数和预装函数组合而成,程序员可以通过函数调用(function call)来调用(invoke)函数,让其完成指定任务。使用函数可使程序区分出许多功能明确的组成部分,简化程序,减少错误。[23]
函数的定义和本质
函数定义包括函数名、参数表列、返回类型和函数体四部分,其一般形式如下:[23]
返回类型 函数名(参数列表) { 语句系列; return 合适的类型数值 }
函数的本质有以下两点:[23]
函数由能完成特定任务的独立程序代码块组成,如有必要,也可调用其他函数来产生最终的输出。[23]函数内部工作对程序的其余部分是不可见的。[23]
输入/输出(I/O)
C++数据的输入与输出是通过I\O流来实现的,I\O流输入或输出的是一系列字节。当程序需要在屏幕上显示输出时,可以使用插入符“<<”向cout输出流中插入字符;当程序需要执行键盘输入时,可以使用提取操作符“>>”从cin输入流中抽取字符。另外,C++的I\O类库提供了一些I\O流控制符,可以直接嵌入到输入/输出语句中来实现 I\O格式控制。[84]
字符串处理
C++中的string.h头文件提供了一些字符串处理库函数。[85]
| 名称 | 作用 |
|---|---|
| 字符串拷贝函数 strcpy(a,b) | 将b拷贝到a中(其中a为字符数组,b可以为字符数组或字符串) |
| sytrncpy(a,b,maxlen) | 最多把b中的n个字符拷贝到a中,当b长度大于 maxlen 时,只把b中的前maxlen个字符拷贝到a中(其中a为字符数组,b可以是字符数组或字符串,maxlen 为正整数) |
| 字符串拼接函数 strcat(a,b) | 将b中的字符拼接到a的后面(其中a为字符数组,b可以为字符数组或字符串) |
| 字符串比较函数 strcmp(a,b) | 若a=b,则返回0;若a>b,返回正整数;若a<b,返回一个负整数(其中a,b均可以为字符数组或字符串) |
| strncmp(a,b,maxlen) | 最多将a和b中的n个字符进行比较,当a,b长度大于maxlen时,maxlen为至多要比较的字符个数(其中a,b可以是字符数组或字符串,maxlen为正整数) |
| strlen(a) | 返回该字符串中的字符个数(不包括“0”) |
数学函数
在 C++ 中并没有相对的运算符可以用来实现开平方根,次方或三角函数等运算。进行这些运算时,程序需要调用定义在头文件<cmath>里 C++ 的标准数学函数库。[86]
| 分类 | 函数名称 | 原型 | 数学表示 | 功能 |
|---|---|---|---|---|
| 绝对值函数 | 整数绝对值函数 | double abs(int i) | 返回参数的绝对值 | |
| 实数绝对值函数 | double fabs(double x) | 返回实数的绝对值 | ||
| 三角函数 | 正弦函数 | double sin(double x) | (为弧度值) | 返回弧度值为的正弦值 |
| 余弦函数 | double cos(double x) | (为弧度值) | 返回弧度值为的余弦值 | |
| 正切函数 | double tan(double x) | (为弧度值) | 返回弧度值为的正切值 | |
| 平方根函数 | double sqrt(double x) | 返回的算术平方根 | ||
| 幂函数 | double pow(double x,double y) | 返回的值 | ||
| 指数、对数函数 | 指数函数 | double exp(double x) | 返回的值 | |
| 自然对数函数 | double log(double x) | 返回以为底的对数 | ||
| 常用对数函数 | double log10(double x) | 返回以10为底的对数 | ||
| 舍入函数 | 向上取整函数 | double ceil(double x) | 返回不小于的最小整数 | |
| 向下取整函数 | double floor(double x) | 返回不大于的最大整数 | ||
| 随机数函数 | 随机函数 | int rand(void) | 返回 0~32767之间的整数 | |
| 改变随机数序列 | void srand(unsigned s) | 生成与对应的随机数序列 | ||
| 终止程序运行 | void exit(int status) | 通常参数为0表示正常结束,非0表示不正常结束 | ||
泛型编程
对于函数或类,若将一些类型定义为类型形参就能描述不同具体类型的共同的结构或行为,使得编程具有通用性,称之为泛型编程(Generic Programming)。[87]其具体要求如下:[88]
程序中的数据组织方法和数据处理算法应该独立于具体的数据类型,可以适用所有的数据类型,并且其效率与针对某特定数据类型而设计的算法相同。例如:以线性结构组织数据时,对于数据元素的类型应该“泛化”,其可以是整数、字符串、数组、文件、类等各种类型。[88]数据组织与数据处理相对独立的同时,两者的耦合关系是“泛型”的。即对于数据处理而言,一种处理方法应该可以作用于所有的数据组织方法;对于数据组织而言,一种组织方法应该可以被作用于所有的数据处理方法。[88]
STL模板库
C++具有的标准模板库(Standard Template Library,STL)是C++代码可重用特性的重要体现,其由Alex Stepanov主持开发,于1998年被加入C++标准。[17]STL是泛型编程的典型代表,其包含了很多基本算法和数据结构,将算法与数据结构完全解耦,使算法不与任何特定数据结构或对象类型绑定(或耦合)在一起,是对类和类模板机制的一种综合应用。[88]
模板
模板(template)是一种类型参量化机制[87],是代码重用的重要手段,是泛型编程的基础,其以一种独立于任何特定数据类型的方式编写代码。模板是对具有相同特性的函数或类的再抽象,是一种参数多态性的工具,为逻辑功能相同而数据类型不同的程序提供一种代码共享的机制。一个模板是对一个函数或类的描述,是参数化的函数和类,而不是一个实实在在的函数或类。[89]定义模板的一般格式和示例如下:[87]
//定义模板的一般格式 template <模板形参表> 函数定义 或 class/struct定义 或 using别名定义 或 变量定义 或 concept定义 //<模板形参表>中至少有一个无名形参,可以有多个类型形参,用逗号隔开
//简单模板示例 template <class> void f() {}; //函数模板,含有1个无名形参 template <class> structA {}; //类模板
| 模板种类 | 说明 | 语法形式 | 实例化结果 |
|---|---|---|---|
| 函数模板 | 用于生成函数的模板: ① 非成员函数模板;②成员函数模板;③ Lambda 函数模板 | template<class T> 函数定义 | 实例函数: ①非成员函数;②成员函数;③ Lambda 表达式 |
| 类模板 | 用于生成类的模板 | template<class T> 类定义 | 实例类 |
| 别名模板 (C++11) | 用于生成类型别名的模板 | template<class T> using 类型别名定义 | 类型别名 |
| 变量模板 (C++14) | 用于生成变量的模板 | template<class T> 变量定义 | 实例变量: ①非成员变量;②成员变量 |
| 概念模板 (C++20) | 用于说明类型约束的模板 | template<class T> concept 概念=约束 | 逻辑值,约束其他模板 |
面向对象程序设计
面向对象程序设计(OOP)是通过为数据和代码建立分块的内存区域来提供对程序进行模块化的一种程序设计方法。对象是一个既含数据又含对数据进行操作的代码的一个逻辑实体或软件构造块,是类的一个实例,每个对象在功能上相互之间保持相对独立;类是这些实体的抽象,是描述面向对象程序设计语言定义的一种数据类型。OOP语言具有封装性、继承性和多态性三个主要性质。[90]
封装性(encapsulation):把数据结构和专门用于操作这些数据的函数或方法结合在一起产生类。[90]继承性(inheritanee):构造的派生类,可以从先前定义的一个或多个基类中继承数据和方法,还可以重新定义或加入新的数据和动作。[90]多态性(polymorphism):可以简单地概括为“一个接口,多种方法”,是面向对象编程领域的核心概念。[90]
类和对象
在C++中,类是用户定义的一种新的数据类型,是数据结构及其密切相关的操作函数的封装体,其明确表达了这种类型数据所能完成的操作。对象是类的一个实例,类似于变量。[91]
一个类由数据和方法两部分组成。使用关键字class来定义一个类,类定义的一般格式和示例如下:[91]
//类的一般格式,类由一些成员组成,它包括数据成员和成员函数。 class <类名> //类名可以是任意的标识符,此标识符在它的作用域内是唯一的 { public: //private、protected、public是访问权限说明符,决定着成员访问权限 <成员函数或数据成员的说明> protected: <成员函数或数据成员的说明> private: <数据成员或成员函数的说明> }; <各个成员函数的实现>
//定义一个学生类,私有成员变量包括:姓名、年龄、性别;公有的成员变量包括:学习 class student{ private: char name[10]; int ages; char sex; public: void study(){}: };
指针
C++ 定义了指针类型,并允许使用指针变量,从而操作地址。[92]
指针类型和指针变量
指针类型:指针类型是一个表示内存位置地址的复合类型,其字面量值是地址。存在指向 char 的指针、指向 int 的指针等。[92]指针变量:指针变量是其内容为指针类型的变量,可以将指针类型的值存储在指针变量中。指针变量的大小在 C++ 中是固定的4字节,可以是一个从0x00000000到0xFFFFFFFF的地址。[92]
地址
内存中的地址:计算机内存是一个字节序列,内存的每个字节都有一个地址,且以十六进制格式表示。例如,在内存为1KB的计算机中,字节的编号从0x0000到0x3FFF。[92]变量的地址:指一个变量所占用的第一个字节的地址。在程序中,可以定义不同类型的变量,每个变量占用一个或者多个字节的内存。例如,bool或者char类型的变量通常占用1个字节的内存。[92]
null 指针和 void 指针
不指向任何对象的指针(null 指针):null 指针是不指向任何内存位置的指针,在 C++语言更倾向于使用字面量0,即当表示指针在当前时刻没有指向任何内存位置,可以将它绑定到0。[92]
指向 void 的指针:void 指针是一个通用指针,可以指向任何类型的对象。[92]
按指针传递和按指针返回
按指针传递:指针可以用于将数据从主调函数传递到被调用函数。在按指针传递中,主调函数将对象(实际参数)的地址传递给被调用函数,被调用函数将其存储在指针(形式参数)中,形式参数的任何更改都意味着实际参数的相同更改。[92]
按指针返回:在按指针返回的方法中,要返回的对象类型是一个指向函数形式参数的指针,其本身则是指向主调函数中的一个对象。[92]
内存管理
C++ 编写的程序运行时,会使用内存位置。同时,代码和每个基本对象或者用户自定义的对象也必须存储在内存中。C++ 环境将内存划分为代码内存、静态内存、栈内存和堆内存四种不同的区域,以使内存管理更加高效。[93]
代码内存:用于存储程序代码。程序运行时,C++ 的运行环境逐条执行每条语句,或者分支跳转到另一条语句,内存区域中不存储任何对象;程序终止时释放代码占用的内存。[93]
静态内存:用于存储全局对象或者静态对象,当程序终止时,这些对象会被自动销毁并被释放内存。[93]栈内存:程序用来保存函数的局部对象或者参数对象的内存部分是栈内存。栈是一个后进先出的容器,最后推入的东西最先弹出,使其适合在函数中存储参数和局部变量。当调用函数时,系统将参数和局部变量推入(push)栈内存中;当函数终止时,系统会弹出(pop)这些变量并丢弃。[93]
堆内存:也称为自由内存或者动态内存,用于存储运行时创建的对象。堆内存适用于当一个对象或者一组对象需要大量内存,或者在编译期间无法计算内存量时。在堆内存中使用运算符 new 和 delete分配和释放内存。[93]
异常处理机制
C++ 提供了一整套面向对象的异常处理机制,其基本思想是将异常的检测与处理分离。C++ 语言异常处理机制将异常定义为类,通过抛出异常对象和截取异常对象两种操作将异常检测和异常处理的逻辑分离。[94]
异常:常把程序运行过程中出现的错误或者意外情况称为异常,如内存溢出、数组下标越界等。[95]异常处理:处理异常的技术就是异常处理。异常处理机制是用于管理程序运行期间错误的一种结构化方法,其将程序中的正常处理代码与异常处理代码显式区别开来,提高了程序的可读性。[95]
C++ 异常处理的实现
C++ 异常处理实现的具体操作由保留字 try、throw 和 catch 实现。其中,try 语句块中通常放入可能出现异常的语句,如果检测到某个语句发生异常,则使用 throw 抛出一个异常对象,catch 负责捕获各种异常并做并做相应外理。[95]
//异常处理流程代码示例 #include <iostream.h> void main() { char *buffer; try { buffer=new char[1024]; if(buffer==0) throw "内存分配错误!"; //throw表达式抛出一个字符串类型的异常 } catch(char *s) //具有char*类型参数的catch子句捕获异常 { cout<<"异常引发:"<<s<<endl; //在存储器分配失败时,程序输出为:异常引发:内存分配错误! } }
异常抛出
throw 语法:当某段程序发现了自己不能处理的异常时,使用 throw 语句将这个异常抛掷给调用者。如果程序中有多处要抛掷异常,应该用不同的表达式类型来互相区别,表达式的值不能用来区别不同的异常。基本表达式如下:[95][96]
throw <表达式>;
try 块语法:try 语句后的复合语句是代码的保护段。如果预料某段程序代码或对某个函数的调用有可能发生异常,就将它放在try 语句之后,当其运行时遇到异常情况时,其中的 throw 表达式就会抛掷这个异常。基本表达式如下:[95][96]
try { 复合语句 }
异常捕获
catch 语句:catch 语句后的复合语句是异常处理程序,捕获由 throw 表达式抛掷的异常。异常类型声明部分指明语句所处理的异常类型,可以是任何有效的数据类型,包括C++的类。当异常被抛掷以后 catch 语句便依次被检查,直到某个 catch 语句的异常类型声明与被抛掷的异常类型一致,则执行该段异常处理程序。基本表达式如下:[95][96]
catch(类型1 参数1) { //针对类型1的异常处理 } catch(类型2 参数2) { //针对类型2的异常处理 } ... catch(类型n 参数n) { //针对类型n的异常处理 }
异常传递:异常传递指的是当一个异常在某个函数中被抛出后,如果该函数没有处理这个异常,即没有捕获这个异常,那么异常将沿着调用栈向上传递,直到找到一个匹配的 catch 块处理它。如果没有找到匹配的 catch 块,程序将调用 std::terminate 函数终止运行。[95][96]
异常自定义
C++ 允许开发者定义自己的异常类,以便更具体地描述异常情况。类 exception 设计为可以继承的,意味着可以根据自己的项目情况派生自定义的异常类型。[97]
标准异常
C++标准库中定义了各种各样预置的异常,这些异常都是Exception类的子类。Exception定义在<exception>头文件中,它的子类大多数都定义在<stdexcept>中,主要包括从 Exception 直接派生的异常类、从 logic_error 派生的逻辑异常和从 runtime_error 派生的运行时异常三种。[98]
局限性
复杂性高:C++ 是一门复杂的语言,有许多的关键字和属性。由于C语言是介于汇编语言和 Basic、Cobol 等高级语言之间的语言,而 C++ 是在C语言的基础上发展而来,因此相比其他语言, C++ 要求更了解计算机芯片和位、字节的知识。[99]易发生内存泄漏:C++ 很容易编写带有微妙错误的程序。例,因为在 C++ 中是对内存进行直接操作,即必须进行内存分配,并在用完后释放该内存。当分配了内存,但没有释放时,该内存对于程序来说就丢失了,就像从程序中泄漏掉了一样。[99]不支持“垃圾回收":自动清除丢失内存的方法称为“垃圾回收",其不是随意的,且会降低应用程序的运行速度,但 C++ 不提供该服务。[99]
易因内存用尽发生程序崩溃:由于 C++ 允许直接对内存进行控制,从而可以对内存进行重写,即可以往内存中直接存值。但当把数值写到错误的内存中时,改变了代码,错误被“移去”了,但是却会在另一处出错,C++程序员很难能够避免花大量的时间来发现这种错误,程序可能会因此用尽内存导致崩溃。[99]
编译器
编译器的功能是将源程序编译成二进制形式的“目标程序(object program)”,同时对源程序的语法进行检查,经过编译后的程序文件以“.obj”为目标程序的拓展名。[57]
| 英文名称 | 运行环境 | 主要特点 |
|---|---|---|
| Intel C++ Compiler(icc、icl) | macOS,Linux、Windows和嵌入式系统 | 兼容GCC,充分发挥Intel多核处理器包括双核移动平台、桌面平台以及企业平台在内的潜能,提高应用程序的性能,同其他广泛使用的编译器保持特性源与二进制方面的兼容性 |
| Borland C++ Builder Compiler | Windows | 包括最后版本的 ANSI/ISO C++ 语言、 RTL、C++ 的STL框架结构的支持 |
| AMD x86 Open64 | Linux | 一套高性能的代码编译工具,其适合并行计算,简化并加速了开发过程,实现了高性能并行化 |
| Watcom C/C++ | Win32、OS/2、Linux、DOS等平台 | 编译后的 exe 可执行文件运行高速,是首个支持Intel 80386 "保护模式"的编译器 |
| Tiny C(TCC) | Windows、Linux、Unix | 可执行文件大小仅为100KB,主要用于具有较小磁盘空间的计算机,例如救援盘;具有可选的内存和越界检查功能,有助于提高代码的稳定性 |
| GNU Compiler(GCC) | Linux、UNIX | 是GNU系统的官方编译器和编译与建立其他操作系统的主要编译器 |
IDE
| 名称 | 运行环境[9][56] | 简要说明 | 图标[100] |
|---|---|---|---|
| Microsoft Visual C++ | Linux、Windows、macOS | 由Microsoft公司开发的,提供标准的C++语言的库函数和MFC(微软基础类库)、方便用户创建一些高级特性的类,使开发人员在一定程度上避免了诸如写任何一个类都要从头开始写的繁琐过程[7] | ![]() |
| Dev C++ | Windows | 使用 MingW32/GCC 编译器,遵循C/C++标准。开发环境包括多页面窗口、工程编辑器以及调试器等,在工程编辑器中集合了编辑器、编译器、连接程序和执行程序,提供高亮度语法显示和完善的调试功能[8] | ![]() |
| Code::Blocks | Linux、Windows、macOS | 一个开源的C/C++的集成开发环境,由纯粹的C++语言开发完成,其开发环境具有较快的响应速度并支持在不同的操作系统下运行[7][56] | ![]() |
| CLion | Linux、Windows、macOS | 一个基于 IntelliJ IDEA 的 C/C++ IDE,提供了代码补全、调试、版本控制、构建、重构等功能,还可以集成其他开发工具和外部应用程序[9] | ![]() |
| Eclipse CDT | Linux、Windows、macOS | 一个开源的 C/C++ 开发工具,是一个功能强大的 IDE,可以提供代码补全、调试、版本控制、构建、重构等功能,插件生态系统丰富[9] | ![]() |
| C-Free | Windows | 一款支持多种编译器的专业化 C/C+集成开发环境,具有完善的代码完成功能和函数参数提示功能,同时还具有大量可定制的功能[56] | ![]() |
| CodeLite | Windows、macos、Ubuntu、FreeBSD 等系统 | 一个开源、跨平台的 C/C++集成开发环境[56] | ![]() |
应用领域
C++ 是一种通用的编程语言,具有高效的运行效率,被广泛应用于嵌入式系统开发、游戏开发等接近系统底层且对运行效率要求高的领域。[101]
系统开发:C++ 具有高效性能和内存控制功能,在系统开发中发挥重要作用,常用于开发操作系统、驱动程序和嵌入式系统等需要高效的资源管理和实时要求的系统。[101]
游戏开发:C++ 是游戏开发的主要编程语言之一,其提供的高性能和精细的内存管理使得游戏开发者能够创建复杂且高效的游戏引擎和游戏。著名的游戏引擎如 Unreal Engine [102]和 Unity[103] 都使用 C++ 进行开发。[104]
图形图像处理:C++ 广泛用于图形和图像处理应用,例如计算机图形学、3D 建模软件、图像编辑工具等。OpenCV[105]等图形库都支持 C++,使得开发者能够创建高性能的图形应用。[104]网络相关:C++ 被广泛应用于网络编程和通信协议的实现,可用于开发高效的网络服务器、客户端程序和网络协议栈。C++ 的性能和可靠性使其成为实现低延迟、高吞吐量网络应用的理想选择。[104]
跨平台开发
跨平台开发是程序设计领域在近些年提出的新的要求,源自于现代软件工程的发展,其主要目的就是要让所开发的应用程序可以在不同类型的平台上顺利运行。Boost等跨平台开发工具和框架已经让C++开发者能够更方便地构建跨平台应用。[106]随着这些工具的不断进步,C++在跨平台开发中的优势将更加明显,使开发者能够更高效地针对多个操作系统和设备进行开发。[107][108]
对分布式计算语言层面的支持
参考资料 109
- 参考 1
- cplusplus — C++ Language Tutorial
- 参考 3
- 参考 4
- Cfront releases — C++ Historical Sources Archive
- 参考 6
- 参考 7
- 参考 8
- C/C++编程环境搭建 — deepin指南
- 参考 10
- 参考 11
- 参考 12
- 参考 13
- 参考 14
- 参考 15
- 参考 16
- 参考 17
- 参考 18
- 参考 19
- 参考 20
- TIOBE Index for May 2024 — TIOBE Index
- 参考 22
- 参考 23
- 参考 24
- 参考 25
- C++ 与 Boost — Boost C++库
- 参考 27
- 参考 28
- 参考 29
- 参考 30
- News, Status & Discussion about Standard C++ — C++
- ISO/IEC 14882:2003 - Programming languages -- C++ — 国际标准化组织
- ISO/IEC 14882:1998 — ISO
- 参考 34
- ISO/IEC TR 14882:2003 — ISO
- C++11 — cppreference.com
- C++14 — cppreference.com
- C++17 — cppreference.com
- C++20 — cppreference.com
- ISO/IEC TR 19768:2007 — ISO
- ISO/IEC TR 29124:2010 — ISO
- ISO/IEC TR 24733:2011 — ISO
- ISO/IEC TS 18822:2015 — ISO
- ISO/IEC TS 19570:2015 — ISO
- ISO/IEC TS 19841:2015 — ISO
- ISO/IEC TS 19217:2015 — ISO
- ISO/IEC TS 19571:2016 — ISO
- ISO/IEC TS 19568:2017 — ISO
- ISO/IEC TS 21425:2017 — ISO
- ISO/IEC TS 22277:2017 — ISO
- ISO/IEC TS 19216:2018 — ISO
- ISO/IEC TS 19570:2018 — ISO
- ISO/IEC TS 21544:2018 — ISO
- 参考 54
- 参考 55
- 参考 56
- 参考 57
- 参考 58
- 参考 59
- 参考 60
- 参考 61
- 参考 62
- 参考 63
- 参考 64
- 参考 65
- 参考 66
- 参考 67
- 参考 68
- 参考 69
- 参考 70
- 参考 71
- 参考 72
- 参考 73
- 参考 74
- 参考 75
- 参考 76
- 参考 77
- 参考 78
- 参考 79
- 参考 80
- 参考 84
- 参考 85
- 参考 86
- 参考 87
- 参考 88
- 参考 89
- 参考 90
- 参考 91
- 参考 94
- 参考 95
- 参考 96
- 参考 97
- 参考 98
- 参考 99
- 最佳 C++ IDE 清单 — 2021 最佳 C++ IDE 排行
- 参考 101
- 参考 102
- Is Unity Engine written in Mono/C#? or C++ — web
- 参考 104
- 参考 105
- 参考 106
- 参考 107
- 参考 108
- 参考 109
注释
- 副作用:此处指更改内存状态;表达式是一个具有可以更改内存状态(称为副作用)的值的实体。[82]
- 程序员定义函数:是程序员用来为定义程序中多处使用的特定任务而编写的函数名称。[23]






