编程语言之CPP
2024-04-14 22:32:44 阿炯

C++(亦写作:CPP)是一种被广泛使用的计算机程序设计语言。它是一种通用程序设计语言,支持多重编程范式,例如过程化程序设计、面向对象程序设计、泛型程序设计和函数式程序设计等。主要实现产品有:Embarcadero C++Builder, GCC, Intel C++ Compiler, Microsoft Visual C++, LLVM Clang等。


在20世纪80年代来自丹麦的比雅尼·斯特劳斯特鲁普(Bjarne Stroustrup)博士在贝尔实验室工作期间发明并实现了C++。起初被称作“C with Classes”(“包含‘类’的C语言”),作为C语言的增强版于1983年正式出现。随后其不断增加新特性,虚函数、运算符重载、多继承、标准模板库、异常处理、运行时类型信息、命名空间等概念逐渐纳入标准草案。1998年,国际标准组织颁布了C++程序设计语言的第一个国际标准ISO/IEC 14882:1998,目前最新标准为ISO/IEC 14882:2020。ISO/IEC 14882通称ISO C++。ISO C++包含了主要包含了核心语言和标准库的规则。尽管从核心语言到标准库都有显著不同,ISO C++直接正式(normative)引用了ISO/IEC 9899(通称ISO C),且ISO C++标准库的一部分和ISO C的标准库的API完全相同,另有很小一部分和C标准库略有差异(例如,strcat等函数提供对const类型的重载)。这使得C和C++的标准库实现常常被一并提供,在核心语言规则很大一部分兼容的情况下,进一步确保用户通常较容易把符合ISO C的源程序不经修改或经极少修改直接作为C++源程序使用,也是C++语言继C语言之后流行的一个重要原因。

作为广泛被使用的免专利工业语言,C++存在多个流行的成熟实现:GCC、基于LLVM的Clang以及Visual C++等。这些实现同时也是成熟的C语言实现,但对C语言的支持程度不一(例如,VC++对ANSI C89之后的标准支持较不完善)。大多数流行的实现包含了编译器和C++部分标准库的实现。编译器直接提供核心语言规则的实现,而库提供ISO C++标准库的实现。这些实现中,库可能同时包含和ISO C标准库的共享实现(如VC++的msvcrt);而另一些实现的ISO C标准库则是单独于编译器项目之外提供的,如glibc和musl。C++标准库的实现也可能支持多种编译器,如GCC的libstdc++库支持GCC的g++和LLVM Clang的clang++。这些不同的丰富组合使市面上的C++环境具有许多细节上的实现差异,因而遵循ISO C++这样的权威标准对维持可移植性显得更加重要。现今讨论的C++语言,除非另行指明,通常均指ISO C++规则定义的C++语言(虽然因为实现的差异,可能不一定是最新的正式版本)。

值得注意,和流行的误解不同,ISO C和ISO C++都从未明确要求源程序被编译(compile),而仅要求翻译(translate),因此C和C++并不是所谓的编译型语言。技术上讲,实现C和C++程序的单位是翻译单元(translation unit)。作为对比,Java语言规范中就明确要求Java程序被编译实现,明确存在编译单元(compilation unit)。实际上C和C++也存在REPL形式的解释器实现,如CINT和Cling。但因为传统上C和C++多以编译器实现,习惯上仍有一些混用,甚至至今仍出现在ISO C++某节标准库条款的标题 (页面存档备份,存于互联网档案馆)上。

传统上,C++语言被视为和C语言实现性能相近的语言,强调运行时的高效。根据《C++编程思想》(Thinking in C++)一书的观点:C++与C的代码执行效率往往相差在±5%之间。其发展大概可以分为三个阶段:第一阶段从80年代到1995年。这一阶段C++语言基本上是传统类型上的面向对象语言,并且凭借着接近C语言的效率,在工业界使用的开发语言中占据了相当大份额;第二阶段从1995年到2000年,这一阶段由于标准模板库和后来的Boost等程序库的出现,泛型程序设计在C++中占据了越来越多的比重。当然,同时由于Java、C#等语言的出现和硬件价格的大规模下降,C++受到了一定的冲击;第三阶段从2000年至今,由于以Loki、MPL(Boost)等程序库为代表的产生式编程和模板元编程的出现,C++出现了发展历史上又一个新的高峰,这些新技术的出现以及和原有技术的融合,使C++已经成为当今主流程序设计语言中最复杂的一员。

设计原则

在《C++语言的设计和演化》(1994)中,Bjarne Stroustrup描述了他在设计C++时,所使用的一些原则;知道这些原则有助于理解C++为何会是现在这个样子。以下总结了一些原则,详尽的内容可参阅该原则文档:
设计成直接的和广泛的支持多种程序设计风格(过程化程序设计、数据抽象、面向对象编程、泛型程序设计)。
设计成给程序设计者更多的选择,即使可能导致程序设计者选择错误。
设计成尽可能与C兼容,借此提供一个从C到C++的平滑过渡。
避免平台限定或没有普遍用途的特性。
不使用会带来额外开销的特性。
设计成无需复杂的程序设计环境。

1998的C++标准分为两个部分:核心语言和C++标准程序库;后者包含了大部分标准模板库和C标准程序库的稍加修改版本。存在许多不属于标准部分的C++程序库,且使用外部链接,程序库甚至可以用C撰写。

特点

和C语言相比,C++引入了更多的特性,包括:复合类型(引用类型等)、const限定符和constexpr常量表达式、类型处理运算符(类型别名及auto和decltype等多种类型指示符)、C++标准库(IO库与多种容器类)与迭代器、动态内存与智能指针、函数重载、面向对象程序设计(如数据抽象、成员函数、类作用域、构造函数与析构函数、静态成员、访问控制与继承、虚函数、抽象类与接口等)、拷贝控制、运算符重载、造型与函数风格的强制类型转换、模板与泛型编程,以及异常处理、命名空间、多继承与虚继承、运行时类型识别及嵌套类等。

C++在某些案例中(见下“与C不兼容之处”),进行比C还要多的类型检查。

以“//”起始作为注解起源自C的前身BCPL,而后被重新引入到C++。

C++的一些特性,C不久之后也采用了,包括在for循环的括号中声明,C++风格的注解(使用//符号,和inline,虽然C99定义的inline关键字与C++的定义不兼容。不过C99也引入了不存在于C++的特性,如:可变参数宏,和以数组作为参数的较佳处理;某些C++编译器可能实现若干特性,以作为扩展,但其余部分并不符合现存的C++特性)

一个常见的混淆其实只是一个微妙的术语问题:由于它的演化来自C,在C++中的术语对象和C语言一样是意味着存储器区域,而不是类的实体,在其它绝大多数的面向对象语言也是如此。大部分的C代码可以很轻易的在C++中正确编译,但仍有少数差异,导致某些有效的C代码在C++中失效,或者在C++中有不同的行为。最常见的差异之一是C允许从void*隐式转换到其它的指标类型,但在C++中这是不被允许。C99去除了一些不兼容之处,也新增了一些C++的特性,如//注释,以及在代码中混合使用。不过C99也纳入几个和C++冲突的新特性(如:可变长数组、原生复数类型和复合逐字常数),而C++11已经加入了兼容C99预处理器的特性。由于C++函数和C函数通常具有不同的名字修饰和调用约定,所有在C++中调用的C函数,须放在extern "C" { /* C函数声明 */ }之内。

Hello World

下面这个程序显示“Hello, world!”然后结束运行:
#include <iostream>
// import <iostream>; // C++20 起
// import std;        // C++23 起

int main() {
    std::cout << "Hello, world!" << std::endl;
    // std::println("Hello, world!"); // C++23 起
    return 0;
}

这里也可以使用using指令以避免多次声明std::——
#include <iostream>
using namespace std;

int main() {
    cout << "Hello, world!" << endl;
    return 0;
}

如果使用“\n”代替以上代码里的“endl”,输出结果相等。

std::cout << "Hello, world!\n";

std::endl 不仅仅会在某个输出流中插入换行字符,还将执行输出流的 flush() 函数(即刷新缓冲区),而'\n'则不会。

C++主要有三个编译阶段:预处理、转译成目标代码和链接(最后的两个阶段一般才视为真正意义上的“编译”)。

争议

“在这12年里,C++用户人数大约每七个月半增加一倍”是许多C++相关文件必引的一段话;然而,时至今日新语言层出不穷,用户人数已不太可能以如此速度增长。分析机构EvansData定期对开发人员展开调查,其资料显示,以C++为工具的开发人员在整个开发界所占的比例由1998年春天的76%下降至2004年秋的46%。一部分Unix/C程序员对C++语言深恶痛绝,其批评的理由如下:
STL以非常丑陋的方式封装了各种数据结构和算法,写出来的代码难以理解、不美观。
C++编译器复杂和不可靠,不适合构建人命关天类型的程序。
Ian Joyner认为面向对象技术徒增学习成本,不如面向过程的C语言简单容易使用,尤其是在系统软件的构建上。

概括说来UNIX程序员批评C++主要是由于UNIX社区与C++社区的文化差异。Linux之父林纳斯·托瓦兹曾经多次炮轰C++。图灵奖得主尼克劳斯·维尔特也曾经批评C++语言太复杂、语法语义模糊,是“拙劣工程学”的成果。事实上,对于C++语言的批评并不只来源于Unix/Unix-Like系统下的程序员。就像C++语言本身是一个跨平台的语言一样,对C++的批评并不局限于Unix/Unix-Like系统用户。


比雅尼·斯特劳斯特鲁普

(丹麦语:Bjarne Stroustrup,丹麦语发音:[ˈbjɑːnə ˈsdʁʌʊ̯ˀsdʁɔb],1950年12月30日—),生于丹麦奥胡斯郡,计算机科学家。他以创造C++编程语言而闻名,被称为“C++之父”。


用他本人的话来说,自己“发明了C++,写下了它的早期定义并做出了首个实现……选择制定了C++的设计标准,设计了C++主要的辅助支持环境,而且负责处理C++标准委员会的扩展提案。”他还写了一本《C++程序设计语言》,它被许多人认为是C++的范本经典,目前是第四版(于2013年5月19日出版),最新版中囊括了C++11所引进的一些新特性。

斯特劳斯特鲁普于1975年获得丹麦奥胡斯大学的数学和计算机科学硕士学位,又于1979年获得英国剑桥大学的计算机科学博士学位。从贝尔实验室大规模编程(Large-scale Programming)研究部门设立至2002年晚些时候,他一直担任那里的负责人。2002年至2014年间,他在得州农工大学工学院担任计算机科学教授一职。2014年1月起,在纽约市的摩根史丹利技术部门担任董事总经理(Managing Director),并于哥伦比亚大学计算机科学系担任客座教授。