C++

C ++
C ++标准委员会认可的徽标
范式多范式程序命令功能面向对象通用模块化
家庭C
设计Bjarne Stroustrup
开发人员ISO / IEC JTC 1(联合技术委员会1) / SC 22(小组委员会22) / wg 21(工作组21)
首先出现1985
稳定版本
C ++ 20 (ISO / IEC 14882:2020) / 2020年12月15日
预览发布
C ++ 2023年3月19日
打字学科静态主格部分推断
作业系统跨平台
文件名扩展.c,.cc,.cpp,.cxx, .c ++ ,.h,.h,.hh,.hh,.hpp,.hxx, .h ++ .cppm,.ixx,
网站isocpp.org
主要实施
GCCLLVM ClangMicrosoft Visual C ++Embarcadero C ++建筑商Intel C ++编译器IBM XL C ++EDG
被影响
ADAALGOL 68BCPLCCLUF#MLMESA ,MOSA, MODULA-2SIMULASMELLTALK
受影响
ADA 95C#C99教堂ClojureDJavaJS ++LuaNimObjective-C ++Perl ,Perl, Php,PythonPythonRustSeed7
  • Wikibooks的C ++编程

C ++ ,发音为“ C Plus ”,有时被缩写为CPP )是由丹麦计算机科学家Bjarne Stroustrup创建的高级通用编程语言。它于1985年首次发行是C编程语言的扩展,此后随着时间的推移大大扩展。截至1997年,C ++具有针对对象通用功能功能,此外还具有低级内存操作的设施。它几乎总是作为一种编译语言实现,许多供应商提供C ++编译器,包括免费软件基金会LLVMMicrosoftIntelEmbarcaderoOracle,OracleIBM

C ++是针对系统编程嵌入式,资源约束的软件和大型系统设计的,具有性能,效率和使用的灵活性,作为其设计的亮点。在许多其他情况下,C ++也被发现有用,关键优势包括软件基础架构和资源受限的应用程序,包括桌面应用程序视频游戏服务器(例如电子商务网络搜索数据库)以及性能至关重要的应用程序(例如电话开关空间探针)。

C ++由国际标准化组织(ISO)标准化,由ISO于2020年12月批准和发布的最新标准版本为ISO/IEC 14882:2020 (非正式地称为C ++ 20 )。 C ++编程语言最初于1998年标准化为ISO/IEC 14882:1998 ,然后由C ++ 03C ++ 11C ++ 14C ++ 17标准进行了修改。当前的C ++ 20标准用新功能和扩大的标准库取代了这些标准。在1998年最初的标准化之前,C ++是自1979年以来在Bell Labs开发的,作为C语言的扩展。他想要一种类似于C的高效且灵活的语言,该语言也为程序组织提供了高级功能。自2012年以来,C ++一直以C ++ 23作为下一个计划的标准制定为期三年的发布时间表。

历史

C ++的创建者Bjarne Stroustrup在他的AT&T新泽西州办公室, c。 2000

1979年,丹麦计算机科学家Bjarne Stroustrup开始从事“C带上C ++的前身。创建一种新语言的动机源自Stroustrup在其博士学位论文中编程的经验。StrousTrup发现Simula具有对大型软件开发非常有用的功能,但该语言太慢了,无法实现。实际用途,虽然BCPL很快,但是太低了,无法适合大型软件开发。当Stroustrup开始在AT&T Bell Labs工作时,他遇到了分析分布式计算的UNIX内核的问题。记住他的博士学位体验,Stroustrup选择使用类似模拟功能来增强C语言。C之所以选择C,是因为它是通用,快速,便携式和广泛使用的。以及C和Simula的影响,其他语言也影响了这种新语言,包括Algol 68,68 ,, ADACLUML

最初,Stroustrup的“ c with Class”添加了C编译器,CPRE,包括派生类强键入内部默认参数

2015年在巴黎给出的C ++ 11个功能的测验

1982年,斯特鲁斯特鲁普(Stroustrup++在浏览其他几个名称后,成为c)中的增量操作员。添加了新功能,包括虚拟功能,功能名称和操作员过载参考,常数,类型安全的免费商店内存分配(新/删除),改进的类型检查以及BCPL样式单行单线注释,带有两个正向斜线(//)。此外,STROUSTRUP开发了一个用于C ++ Cfront的新的独立编译器。

1984年,Stroustrup实施了第一个流输入/输出库。道格·麦克罗伊(Doug McIlroy)提出了提供输出运算符而不是命名输出功能的想法(他以前曾建议UNIX管道)。

1985年,发行了C ++编程语言的第一版,该语言成为该语言的确定性参考,因为尚无官方标准。 C ++的首次商业实施于同年10月发布。

1989年,发布了C ++ 2.0,随后在1991年更新了C ++编程语言的第二版。2.0中的新功能包括多个继承,抽像类,静态成员函数, const成员函数和受保护的成员。 1990年,出版了注释的C ++参考手册。这项工作成为未来标准的基础。后来的功能添加包括模板异常名称空间,新铸件布尔类型

1998年,发布了C ++ 98,标准化了语言,并于2003年发布了次要更新( C ++ 03 )。

在C ++ 98之后,C ++进化相对较慢,直到2011年发布C ++ 11标准,添加了许多新功能,进一步扩大了标准库,并为C ++程序员提供了更多的设施。在2014年12月发布了次要C ++ 14更新后, C ++ 17中引入了各种新添加。在2020年2月最终完成后,C ++ 20标准的草案于2020年9月4日批准,并于2020年12月15日正式发布。

2018年1月3日,Stroustrup被宣布为Charles Stark Draper工程奖的2018年获奖者,“概念化和开发C ++编程语言”。

截至2022年12月,C ++在TIOBE指数上排名第三,在该指数历史上首次超过Java 。在PythonC之后,它排名第三。

词源

根据Stroustrup的说法,“名称表示C变化的进化性质”。这个名字被称为里克·玛斯蒂蒂(Rick Mascitti)(1983年中),并于1983年12月首次使用。当玛西蒂(Mascitti)在1992年非正式地质疑有关该命名的人时,他表示,它是用嘲讽的精神给予的。这个名字来自C的++运算符(会增加变量)和使用“+”表示增强的计算机程序的常见命名约定

在C ++的开发期间,该语言被称为“新C”和“与类”,然后获得其最终名称。

哲学

在整个C ++的生活中,其发展和进化都受到一组原则的指导:

  • 它必须由实际问题驱动,其功能应立即在现实世界计划中有用。
  • 每个功能都应实现(采用相当明显的方法)。
  • 程序员应该可以自由选择自己的编程样式,并且该样式应由C ++完全支持。
  • 允许使用有用的功能比防止所有可能滥用C ++更重要。
  • 它应该为将程序组织成各个定义明确的零件提供设施,并提供与单独开发零件相结合的设施。
  • 没有对类型系统的隐性违规行为(但允许明确违规;即程序员明确要求的违规行为)。
  • 用户创建的类型需要与内置类型具有相同的支持和性能。
  • 未使用的功能不应对创建的可执行文件产生负面影响(例如,性能较低)。
  • C ++下面不应有语言(汇编语言除外)。
  • C ++应与其他现有的编程语言一起工作,而不是培养自己的独立且不兼容的编程环境
  • 如果程序员的意图未知,请允许程序员通过提供手动控制来指定它。

标准化

1996年在斯德哥尔摩举行的C ++标准委员会会议上的场景
C ++标准
ISO/IEC标准非正式名称
199814882:1998C ++ 98
200314882:2003C ++ 03
201114882:2011C ++ 11 ,C ++ 0x
201414882:2014C ++ 14 ,C ++ 1y
201714882:2017C ++ 17 ,C ++ 1z
202014882:2020C ++ 20 ,C ++ 2A
2023C ++ 23

C ++由称为JTC1/SC22/WG21的ISO工作组标准化。到目前为止,它已经发布了C ++标准的六个修订版,目前正在下一个修订版C ++ 23

1998年,ISO工作组首次标准化C ++为ISO/IEC 14882:1998 ,非正式地称为C ++ 98 。 2003年,它发布了一个名为ISO/IEC 14882:2003的C ++标准的新版本,该标准固定了C ++ 98中确定的问题。

该标准的下一个重大修订版被非正式地称为“ C ++ 0x”,但直到2011年才发布。C++ 11 (14882:2011)都包含了核心语言和标准库的许多补充。

2014年, C ++ 14 (也称为C ++ 1Y)被发布为C ++ 11的小扩展名,主要是错误修复和小改进。国际标准投票程序草案于2014年8月中旬完成。

在C ++ 14之后,ISO C ++委员会于2017年7月中旬完成了一项主要的C ++ 17 ,非正式地称为C ++ 1Z,并于2017年12月批准并发布。

作为标准化过程的一部分,ISO还发布了技术报告和规格

  • ISO/IEC TR 18015:2006关于在嵌入式系统中使用C ++以及C ++语言和库功能的性能含义,
  • ISO/IEC TR 19768:2007(也称为C ++技术报告1 ),主要集成到C ++ 11中,
  • ISO/IEC TR 29124:2010在特殊数学功能上,集成到C ++ 17
  • ISO/IEC TR 24733:2011在小数浮点算术上,
  • ISO/IEC TS 18822:2015在标准文件系统库上,集成到C ++ 17
  • ISO/IEC TS 19570:2015在标准库算法的并行版本上,集成到C ++ 17
  • ISO/IEC TS 19841:2015关于软件交易记忆
  • ISO/IEC TS 19568:2015在一组新的图书馆扩展程序上,其中一些已经集成到C ++ 17中,
  • ISO/IEC TS 19217:2015在C ++概念上,集成到C ++ 20
  • ISO/IEC TS 19571:2016在图书馆扩展方面的并发,其中一些已经集成到C ++ 20
  • ISO/IEC TS 19568:2017在一套新的通用库扩展程序上
  • ISO/IEC TS 21425:2017在图书馆扩展范围内,集成到C ++ 20
  • ISO/IEC TS 22277:2017在Coroutines上,集成到C ++ 20
  • ISO/IEC TS 19216:2018在网络库上
  • ISO/IEC TS 21544:2018在模块上,集成到C ++ 20
  • ISO/IEC TS 19570:2018在一套新的并行库扩展程序上
  • ISO/IEC TS 23619:2021在新的反思上

更多的技术规格正在开发和未决批准,包括新的并发扩展。

语言

C ++语言具有两个主要组成部分:主要由C子集提供的硬件功能的直接映射,而基于这些映射的零偏抽摘要。 Stroustrup将C ++描述为“一种轻巧的抽象编程语言(设计),用于构建和使用高效,优雅的抽象”;并且“提供硬件访问和抽像是C ++的基础。有效地做到这一点是将其与其他语言区分开来的。”

C ++继承了C的大多数语法。以下是Bjarne Stroustrup的Hello World程序版本,该程序使用C ++标准库流动工具将消息写入标准输出

#include <iostream>

int main()
{
    std::cout << "Hello, world!\n";
}

对象存储

如C所示,C ++支持四种类型的内存管理:静态存储持续时间对象,线程存储持续时间对象,自动存储持续时间对象和动态存储持续时间对象。

静态存储持续时间对象

在创建静态存储持续时间之前是main()输入(请参见下面的例外),并以相反的创建顺序被破坏main()退出。标准未指定的确切创建顺序(尽管有一些规则定义了一些规则),以允许实现如何组织其实施方案。更正式的是,这种类型的对象具有“在程序持续时间内持续的寿命”。

静态存储持续时间对像以两个阶段初始化。首先,执行“静态初始化”,只有在执行所有静态初始化,才能执行“动态初始化”。在静态初始化中,所有对象首先用零初始化;之后,所有具有恒定初始化阶段的对象均以恒定表达式初始化(​​IE变量用文字或constexpr)。尽管未在标准中指定它,但静态初始化阶段可以在编译时完成并保存在可执行文件的数据分区中。动态初始化涉及通过构造函数或函数调用完成的所有对像初始化(除非标记了函数constexpr,在C ++ 11中)。动态初始化顺序定义为编译单元中声明的顺序(即同一文件)。关于编译单元之间的初始化顺序没有保证。

线程存储持续时间对象

这种类型的变量与静态存储持续时间对象非常相似。主要区别是创建时间就在线程创建之前,并且在线程连接后进行破坏。

自动存储持续时间对象

C ++中最常见的变量类型是函数或块中的局部变量,以及临时变量。关于自动变量的共同特征是它们的寿命仅限于变量的范围。它们是在声明点创建并有可能初始化的(有关详细信息,请参见下文),并在剩余范围时以创建的相反顺序销毁。这是通过堆栈上的分配来实现的。

当执行点通过声明点时,创建本地变量。如果变量具有构造函数或初始化器,则用于定义对象的初始状态。当关闭其声明的本地块或函数时,局部变量将被破坏。在对象寿命的末尾调用了本地变量的C ++破坏者,允许对称为RAII的自动资源管理的学科,该纪律被广泛用于C ++。

创建父对象时创建成员变量。数组成员从0到阵列的最后一个成员以顺序初始化。当父对像以创建的相反顺序破坏时,会员变量将被破坏。即,如果父母是“自动对象”,那么它将在范围内触发所有成员的破坏时被破坏。

由于表达评估的结果而创建临时变量,并在包含表达式的陈述已得到充分评估时被破坏(通常在;在声明结束时)。

动态存储持续时间对象

这些对象具有动态寿命,可以直接创建new并通过打电话明确摧毁delete。 C ++也支持mallocfree,来自C,但这些与newdelete。用于new返回分配的内存的地址。 C ++核心指南建议不要使用new直接用于创建动态对象,以支持智能指针make_unique<T>用於单一所有权和make_shared<T>用于参考分数的多重所有权,在C ++ 11中引入。

模板

C ++模板启用通用编程。 C ++支持功能,类,别名和可变模板。模板可以通过类型,编译时间常数和其他模板进行参数化。模板是通过编译时实例化实现的。为了实例化模板,编译器将特定参数替换为模板的参数以生成混凝土函数或类实例。不可能进行一些替代;这些用“替换失败不是错误”(Sfinae)所描述的过载分辨率策略消除了这些。模板是一种功能强大的工具,可用于通用编程模板元编程和代码优化,但是此功能意味着成本。模板使用可能会增加对象代码大小,因为每个模板实例化都会产生模板代码的副本:一个用于每组模板参数的副本,但是,如果代码是手工编写的,则该代码是相同或较小的代码。这与其他语言(例如Java )中看到的运行时代相反,在该语言中,在编译时删除了类型并保留单个模板主体。

模板与不同:尽管这两种编译时语言特征都可以使有条件的汇编,但模板不仅限于词汇替代。模板知道其伴随语言的语义和类型系统以及所有编译时类型的定义,并且可以根据对严格类型检查的参数的评估进行高级操作,包括程序化流量控制。宏能够根据预定的标准有条件地控制汇编,但无法实例化新类型,重复或执行类型评估,并且实际上仅限于兼容的文本裁定和文本包含/排除。换句话说,宏可以根据预定义的符号控制汇编流,但与模板不同,独立实例化了新符号。模板是静态多态性(见下文)和通用编程的工具。

此外,模板是C ++中的编译时间机制,它是Turing-Complete的,这意味着可以通过运行时通过模板元数据以某种形式计算计算机程序表达的任何计算。

总而言之,模板是编译时间的参数化函数或书面的类别,而无需了解用于实例化的特定参数。实例化后,结果代码等效于专门为传递参数编写的代码。通过这种方式,模板提供了一种将功能和类(以模板编码)(用模板参数编码)编码的通用,广泛适用的方面(在模板参数中编码)的方法,而无需牺牲抽象引起的绩效。

对象

C ++将面向对象的编程(OOP)功能引入C。它提供了,提供了OOP(和某些非oop)语言中通常存在的四个功能:抽象封装继承多态性。与其他编程语言中的类相比,C ++类的一个显著特征是对确定性破坏者的支持,这反过来又提供了对资源获取的支持是初始化(RAII)概念。

封装

封装是信息的隐藏,以确保按预期使用数据结构和运算符,并使开发人员更明显。 C ++提供了将类和功能定义为其主要封装机制的能力。在班级中,可以将成员声明为公共,受保护或私人以明确执行封装。任何功能都可以访问班级的公共成员。私人成员仅适用于该类成员的功能,以及该类明确授予访问权限的功能和类(“朋友”)。除了班级本身和任何朋友外,还可以访问从课堂上继承的课程成员。

面向对象的原理可确保全部封装,并且仅访问类型的内部表示的函数。 C ++通过成员函数和朋友功能支持此原理,但并未强制执行。程序员可以声明零件或所有类型的代表为公开,并且可以使公共实体不参与类型的代表。因此,C ++不仅支持面向对象的编程,还支持其他分解范式,例如模块化编程

通常,将所有数据私有或受保护,并仅公开这些功能是班级用户最小界面的一部分。这可以隐藏数据实现的详细信息,从而使设计人员以后可以从根本上更改实现,而无需以任何方式更改接口。

遗产

继承允许一种数据类型获取其他数据类型的属性。从基类的继承可以被宣布为公共,受保护或私人。此访问说明符确定无关和派生的类是否可以访问基类的继承的公共和受保护成员。只有公共继承就对应于“继承”通常含义。其他两种形式的使用频率要少得多。如果省略了访问说明符,则“类”将私下继承,而“ struct”将公开继承。基础类可能被宣布为虚拟;这称为虚拟继承。虚拟继承可确保继承图中仅存在一个基类实例,从而避免了多个继承的某些歧义问题。

多元继承是C ++功能,可以从多个基类派生。这允许更复杂的继承关系。例如,“飞行猫”课可以从“猫”和“飞行哺乳动物”中继承。其他一些语言(例如C#Java) ,通过允许继承多个接口来完成类似的事情(尽管更有限),同时将基类数量限制为一个(界面,与类别不同,仅提供成员函数的声明,没有实现或成员的声明数据)。 C#和Java中的接口可以在C ++中定义为仅包含纯虚拟函数的类,通常称为抽象基类或“ ABC”。这种抽象基类的成员函数通常在派生类中明确定义,而不是隐式继承。 C ++虚拟继承表现出称为优势的歧义分辨率。

操作员和操作员超载

无法超负荷的操作员
操作员象征
范围分辨率运算符::
有条件的操作员?:
点操作员.
会员选择操作员.*
大小”操作员sizeof
TypeID ”操作员typeid

C ++提供了35多个运营商,涵盖基本算术,位操纵,间接,比较,逻辑操作等。几乎所有运营商都可以超载用户定义的类型,但有一些值得注意的例外(例如成员访问)(..*)以及条件操作员。丰富的超载运算符集对于使C ++中的用户定义类型看起来像内置类型至关重要。

可超载运算符也是许多高级C ++编程技术(例如智能指针)的重要组成部分。超载运算符不会更改涉及操作员的计算的优先级,也不会更改操作员使用的操作数(但是,操作数可能会被操作员忽略,尽管将在执行之前对其进行评估)。超负荷”&&“ 和 ”||“操作员将失去其短路评估属性。

多态性

多态性使许多实现的常见界面可以使对像在不同的​​情况下采取不同的作用。

C ++支持几种静态(在编译时解决)和动态(在运行时解决)多态性,并得到上述语言特征的支持。编译时多态性不允许某些运行时决策,而运行时多态性通常会造成绩效惩罚。

静态多态性

功能过载允许程序声明具有相同名称但具有不同参数的多个功能(即临时多态性)。功能由其形式参数的数量或类型来区分。因此,相同的函数名称可以根据使用的上下文来参考不同的函数。该功能返回的类型不用于区分过载函数,而不同的返回类型将导致编译时错误消息。

声明函数时,程序员可以为一个或多个参数指定默认值。这样做允许在调用函数时可选地省略具有默认值的参数,在这种情况下,将使用默认参数。当调用一个函数的参数少于声明的参数时,明确的参数与从左到右顺序的参数匹配,并且在分配了参数列表末尾的任何无与伦比的参数正在分配其默认参数。在许多情况下,在单个函数声明中指定默认参数比提供不同数量参数的过函数定义更可取。

C ++中的模板提供了编写通用,多态性代码(即参数多态性)的复杂机制。特别是,通过奇怪的重复模板模式,可以实现一种静态多态性形式,该形式紧密模仿了覆盖虚拟函数的语法。由于C ++模板是类型的感知和Turing-Complete ,因此它们也可以用来使编译器解决递归条件并通过模板元编程生成实质性程序。与某些意见相反,模板代码在使用适当的编译器设置进行编译后不会生成批量代码。

动态多态性

遗产

C ++中的可变指针和对基类类型的引用也可以指该类型的任何派生类的对象。这允许数组和其他类型的容器将指针固定在不同类型的对像上(引用不能直接保存在容器中)。这使动态(运行时)多态性能够根据其(实际,派生的)类型的不同,在这种情况下,引用对象的行为可能会有所不同。

C ++也提供dynamic_cast操作员允许代码通过基本参考/指针安全地尝试将对象转换为更衍生的类型:降低尝试是必要的,因为人们经常不知道引用哪种派生类型。 (升级,转换为更通用的类型,始终可以在编译时间检查/执行static_cast,由于在派生类的界面中指定了祖先类,因此所有呼叫者都可以看到。dynamic_cast依靠运行时类型信息(RTTI),程序中的元数据,可以使类型及其关系及其关系。如果一个dynamic_cast指针失败,结果是nullptr常数,而如果目标是参考(不能为null),则铸件会引发异常。已知的某种派生类型已知的对象可以使用static_cast,绕过RTTI和安全的运行时类型检查dynamic_cast,因此,只有在程序员非常有信心演员阵容是有效的情况下,才应使用此功能。

虚拟成员功能

通常,当派生类中的函数覆盖基类中的函数时,要调用的函数由对象的类型确定。当两个或多个函数定义之间的参数数量或类型没有差异时,给定的函数就会被覆盖。因此,在编译时,可能无法确定对象的类型,因此仅给定一个基类指针,可以调用正确的函数;因此,该决定被推迟到运行时。这称为动态调度。根据对象的实际运行时类型,虚拟成员函数方法允许调用该函数的最特定实现。在C ++实现中,这通常是使用虚拟功能表完成的。如果已知对像类型,则可以通过在函数调用之前准备一个完全合格的类名称来绕过这一点,但是在运行时,对虚拟函数的一般调用将解决。

除了标准成员功能外,操作员的过载和破坏者可能是虚拟的。基于实际经验的不精确规则指出,如果班级中的任何功能是虚拟的,则灾难也应该是。由于在编译时间和扩展复制构造函数的编译时,其创建中的对象的类型是虚拟的。尽管如此,可能会出现一个情况,如果将对象的副本作为指向基本对象的指针传递时,需要创建对象的副本。在这种情况下,一个常见的解决方案是创建一个clone()(或类似的)虚拟函数在调用时会创建并返回派生类的副本。

也可以通过将成员函数附加到“纯虚拟”= 0结束后括号和半圆龙之前。包含纯虚拟函数的类称为抽像类。无法从抽像类创建对象;它们只能源自。任何派生的类都将虚拟函数继承为纯净的函数,并且必须在可以创建派生类的对象之前对其(以及所有其他纯虚拟函数)提供非伪定义(以及所有其他纯虚拟函数)。试图创建具有纯虚拟成员函数或继承的纯虚拟成员函数的类对象的程序是错误的。

lambda表达式

C ++为匿名函数(也称为Lambda表达式)提供了支持,并具有以下形式:

[capture](parameters) -> return_type { function_body }

自C ++ 20以来,关键字template对于Lambda表达式的模板参数是可选的:

[capture]<template_parameters>(parameters) -> return_type { function_body }

如果Lambda不采用参数,并且不使用返回类型或其他指定符,则可以省略(),也就是说

[capture] { function_body }

如果可能的话,可以自动推断出lambda表达式的返回类型,例如:

[](int x, int y) { return x + y; } // inferred
[](int x, int y) -> int { return x + y; } // explicit

[capture]列表支持关闭的定义。这种lambda表达式在标准中定义为无名函数对象句法糖

异常处理

异常处理用于传达运行时问题的存在或从检测到问题的地方的错误。它允许以统一的方式进行操作,并在检测所有错误时与主代码分开进行。如果发生错误,则会抛出异常(升高),然后被最近的合适异常处理程序捕获。例外会导致当前范围退出,也导致每个外部范围(繁殖)直到找到合适的处理程序,然后依次调用这些退出的范围中任何对象的破坏者。同时,一个例外是携带有关检测问题的数据的对象。

某些C ++样式指南,例如Google的LLVM和QT,禁止使用异常。

引起异常的代码放置在一个try堵塞。例外是在分开的catch块(处理程序);每个try块可以具有多个异常处理程序,因为在下面的示例中可见。

#include <iostream>
#include <vector>
#include <stdexcept>

int main() {
    try {
        std::vector<int> vec{3, 4, 3, 1};
        int i{vec.at(4)}; // Throws an exception, std::out_of_range (indexing for vec is from 0-3 not 1-4)
    }
    // An exception handler, catches std::out_of_range, which is thrown by vec.at(4)
    catch (const std::out_of_range &e) {
        std::cerr << "Accessing a non-existent element: " << e.what() << '\n';
    }
    // To catch any other standard library exceptions (they derive from std::exception)
    catch (const std::exception &e) {
        std::cerr << "Exception thrown: " << e.what() << '\n';
    }
    // Catch any unrecognised exceptions (i.e. those which don't derive from std::exception)
    catch (...) {
        std::cerr << "Some fatal error\n";
    }
}

也可以使用throw关键词;这些例外以通常的方式处理。在某些情况下,由于技术原因不能使用例外。一个这样的示例是嵌入式系统的关键组成部分,必须保证在指定的时间内完成每个操作。这不能在例外确定,因为没有工具可以确定要处理的例外所需的最大时间。

信号处理不同,从故障点调用处理函数,异常处理在输入捕获块之前退出当前范围,该范围可能位于当前函数或当前堆栈上当前的任何先前函数调用中。

枚举类型

C ++具有直接从C的枚举类型,并且主要像这样的工作,只是枚举是C ++的真实类型,提供了添加的编译时间检查。也(与结构一样),C ++enum关键字与typedef ,这样而不是命名类型enum name,只需命名name。可以使用Typedef在C中模拟这:typedef enum {Value1, Value2} name;

C ++ 11还提供了第二种枚举,称为范围枚举。这些是类型安全的:枚举者不会隐式转换为整数类型。除其他外,这允许为枚举类型定义I/O流媒体。范围枚举的另一个功能是枚举者不会泄漏,因此用法需要以枚举的名称前缀(例如,例如,Color::Red对于下面的示例中的第一个枚举者),除非using enum声明(在C ++ 20中引入)已用于将枚举者带入当前范围。用词组指定了范围的枚举enum class(或者enum struct)。例如:

enum class Color {Red, Green, Blue};

枚举的基本类型是实现定义的积分类型,足够大以保持所有枚举值;它不必是最小的类型。可以直接指定基础类型,这允许枚举的“正向声明”:

enum class Color : long {Red, Green, Blue};  // must fit in size and memory layout the type 'long'
enum class Shapes : char;  // forward declaration. If later there are values defined that don't fit in 'char' it is an error.

标准库

被批准为C ++ 98的“工作文件”标准草案;其大小的一半专用于C ++标准库。

C ++标准由两个部分组成:核心语言和标准库。 C ++程序员期望C ++的每项主要实施中有后者;它包括聚合类型(向量,列表,地图,集合,队列,堆栈,阵列,元组),算法(查找, for_each ,for_each, binary_search ,Random_shuffle等),输入/输出设施( iostream ,iostream,用于从和写作,以读取到读取到书面控制台和文件),文件系统库,本地化支持,用于自动内存管理的智能指针正则表达式支持,多线程库,原子支持(允许一次读取变量或最多由一个线程读取或编写,而无需任何外部线程同步),时间实用程序(测量,获取当前时间等),一个用于转换错误报告的系统,该系统不使用C ++例外为C + +异常,随机数生成器C标准库的稍微修改的版本符合C ++类型系统)。

C ++库的很大一部分基于标准模板库(STL)。 STL提供的有用工具包括容器作为对象的集合(例如向量列表),可提供类似数组的容器访问的迭代以及执行诸如搜索和分类之类的操作的算法

此外,还提供了(多)地图(关联阵列)和(多)集,所有这些导出兼容接口。因此,使用模板可以编写与任何容器或迭代器定义的任何序列一起使用的通用算法。与C中一样,功能可以通过使用#include指令包括标准标头C ++标准库提供105个标准标头,其中27个已弃用。

该标准融合了最初由亚历山大·斯蒂芬诺夫(Alexander Stepanov)设计的STL,后者使用通用算法和容器进行了多年的实验。当他从C ++开始时,他终于找到了一种语言,可以在其中创建一般算法(例如,STL Sort),其性能甚至比C c Standard Library Qsort更好,这要归功于C ++的功能,例如使用Innlining和Compile-compile-时间绑定而不是功能指针。该标准并不称其为“ stl”,因为它仅仅是标准库的一部分,但是该术语仍然被广泛用于将其与标准库的其余部分区分开(输入/输出流,国际化,诊断, C库子集等)。

大多数C ++编译器以及所有主要编译器都提供了C ++标准库的标准配合实现。

C ++核心指南

C ++核心指南是由C ++的发明者Bjarne Stroustrup和C ++ ISO工作组的召集人兼主席Herb Sutter领导的一项计划,以帮助程序员通过使用最佳实践C+标准C+语言来帮助编写“现代C ++”。 +11和更新,并帮助编译器和静态检查工具的开发人员创建用于捕捉不良编程实践的规则。

主要目的是有效,始终如一地编写类型和资源安全的C ++。

核心准则在CPPCON 2015的开幕主题演讲中宣布。

该指南伴随着指南支持库(GSL),该指南唯一的类型和功能库,以实现核心准则和静态检查器工具来执行指南规则。

相容性

为了赋予编译器供应商更大的自由度,C ++标准委员会决定不决定执行名称杂交异常处理和其他特定于实施功能的实施。该决定的缺点是,不同编译器产生的对象代码有望不兼容。但是,尽管现在似乎已经放弃了很大程度上放弃了特定机器或操作系统(例如C ++ ABI)的编译器标准化。

与c

C ++通常被认为是C的超集C ,但这并非严格。大多数C代码都可以轻松地在C ++中正确编译,但是有一些差异会导致某些有效的C代码无效或在C ++中行为不同。例如,C允许从void*对于其他指针类型,但C ++没有(出于类型的安全原因)。另外,C ++定义了许多新关键字,例如newclass,可以用作C程序中的标识符(例如,可变名称)。

1999年修订C标准( C99 )已删除了一些不兼容,该修订版现在支持C ++功能,例如行评论(//)和声明与代码混合。另一方面,C99引入了许多新功能C ++不支持C ++中不兼容或多余的新功能,例如可变长度阵列,本机复杂数字类型(但是,std::complexC ++标准库中的类提供类似的功能,尽管不兼容代码),指定的初始化器,复合文字restrict关键词。 C99引入的某些特征包括在C ++标准的后续版本中, C ++ 11 (在那些不是冗余的版本中)。但是,C ++ 11标准引入了新的无兼容性,例如将字符串字面的分配为字符指针,该指针保持有效。

对于Intermix C和C ++代码,必须通过将其放置在C和C ++中的任何函数声明或定义。extern "C" {/*...*/}堵塞。这样的功能可能不依赖于名称杂交(即功能过载)的功能。

批评

尽管采用了广泛的采用,但一些著名的程序员还是批评了C ++语言,包括Linus TorvaldsRichard StallmanJoshua BlochKen​​ ThompsonDonald Knuth

C ++最常见的观点之一是它认为复杂性是一种语言,并批评说,实践中有大量的非正交特征需要将代码限制为C ++的一部分,从而避免了常见风格和习惯的可读性优势。正如约书亚·布洛克(Joshua Bloch)所表达的那样:

我认为C ++被远远超出了其复杂性阈值,但是有很多人对其进行编程。但是,您要做的是迫使人们将其征服。因此,几乎我知道的几乎每家商店都使用C ++说:“是的,我们正在使用C ++,但我们没有执行多次实施继承,也没有使用操作员过载。”您只会使用一堆功能,因为结果代码的复杂性太高。而且,当您必须开始这样做时,我认为这是不好的。您将失去这个程序员的可移植性,每个人都可以阅读其他所有人的代码,我认为这是一件好事。

唐纳德·诺斯(Donald Knuth ,1993年,评论了预标准化的C ++),他谈到Edsger Dijkstra说:“想想C ++中的编程”“会让他身体不适”:

我今天与他们遇到的问题是... C ++太复杂了。目前,除非我避免所有异国情调的功能,否则我认为我不可能编写可用于许多不同系统的便携式代码。每当C ++语言设计师就如何解决问题的方式有两个相互竞争的想法时,他们说:“好,我们会做的”。因此,这种语言太巴洛克式了。

贝尔实验室(Bell Labs)的Stroustrup同事肯·汤普森(Ken Thompson)对他的评估进行了评估:

它当然有好观点。但是总的来说,我认为这是一种坏语言。它做了很多一半的事情,这只是互斥的垃圾堆。我认识的每个人,无论是个人还是公司,都选择一个子集,而这些子集则不同。因此,运输算法不是一个好语言,说:“我写了;在这里,拿走它。”太大了,太复杂了。它显然是由委员会建造的。斯特鲁斯特鲁普(Stroustrup)竞选了多年和几年,超出了他对语言所做的任何技术贡献,以使其采用和使用。他用鞭子和主席负责所有标准委员会。他对没有人说“不”。他将所有功能都以曾经存在的语言为单位。它的设计不是干净的 - 只是随之而来的一切的结合。我认为这遭受了巨大的痛苦。

但是,贝尔实验室的同事布莱恩·克尼根(Brian Kernighan)对此评估提出异议:

C ++具有极大的影响。 ...很多人说C ++太大了,太复杂了。 ,实际上是试图解决现实世界问题的人们。现在,我们今天使用的许多程序都是C ++程序。

Stroustrup本人评论说,C ++语义比其语法要干净得多:“在C ++中,有一种努力挣扎的语言要小得多”。

其他投诉可能包括缺乏反射垃圾收集,较长的汇编时间,感知的特征蠕变和详细错误消息,尤其是来自模板元编程。

也可以看看