Cpp简史
# 第 1 章 C++ 简史与版本演进(C++98 → C++23)
本章定位:让你在动手写第一行代码之前,先看清整门语言的"骨骼"。 读完后你会明白:为什么 C++ 看起来"既古老又现代"、不同书里"为什么写法差别这么大"、面试官问"你用的是 C++ 几"到底在问什么。
# 目录介绍
- 01.为什么先讲历史
- 02.C++ 的诞生(1979-1985)
- 03.标准化时代(1998-2003)
- 04.停滞的十年(2003-2011)
- 05.现代 C++ 的开端:C++11
- 06.稳定演进期:C++14 / C++17
- 07.再次革命:C++20
- 08.最新版本:C++23 / C++26 展望
- 09.如何在项目中选择 C++ 版本
- 10.本章新手陷阱 Top 5
- 11.思考题
- 12.推荐阅读
# 01.为什么先讲历史
# 1.1 C++ 学习曲线陡峭的根本原因
C++ 难学,不是难在指针,也不是难在模板,而是难在它同时存在三套写法:
// 写法 A:1985 年的 C++("C with Classes"风格)
char* name = (char*)malloc(64);
strcpy(name, "C++");
free(name);
// 写法 B:2003 年的 C++("Effective C++ 1st"风格)
std::string* name = new std::string("C++");
// ... 必须记得 delete,否则内存泄漏
delete name;
// 写法 C:2017 年以后的现代 C++
std::string name = "C++"; // 栈对象,自动释放,零负担
2
3
4
5
6
7
8
9
10
11
12
三套写法至今都能编译过、都能跑通,导致同样一个问题"如何动态分配字符串",你在网上能搜到至少十几种"答案"。
本书要做的第一件事,就是告诉你哪一种写法"正确而现代"。
# 1.2 历史就是"为什么这样写"的答案
读完本章你会明白:
- 为什么
using namespace std;在大型项目里被禁用 → C++98 标准库才搬进std - 为什么有
NULL还要再来个nullptr→ C++11 修复了NULL的类型歧义 - 为什么有
typedef还要再来个using→ C++11 提供了模板别名 - 为什么有
0/NULL/nullptr三种空指针 → 历史包袱 - 为什么
std::vector<bool>是个"特殊的怪物" → C++98 的优化设计失误 - 为什么三路比较
<=>是 C++20 的明星特性 → 从前每个比较类要写 6 个运算符
# 1.3 本章学习目标
- 知道 C++ 从 1979 年到 2023 年的关键时间节点
- 能脱口说出 C++11 / 14 / 17 / 20 / 23 各自的 3-5 个标志性特性
- 在简历上正确填写"我熟悉 C++17/C++20"而不被面试官追问到崩溃
- 在团队会议上能说出"我们应该升级到 C++17 因为……"
# 02.C++ 的诞生(1979-1985)
# 2.1 Bjarne Stroustrup 与 Simula 的灵感
1979 年,丹麦计算机科学家 Bjarne Stroustrup(本贾尼·斯特劳斯特卢普) 在贝尔实验室攻读博士时,需要为分布式系统模拟编写代码。
他面对一个两难选择:
| 选择 | 优点 | 缺点 |
|---|---|---|
| Simula 67 | 有面向对象、类、继承 | 慢得无法用于工程 |
| BCPL / C | 飞快 | 没有抽象能力,写大型系统极痛苦 |
他做了一个决定:给 C 加上 Simula 的类。
这就是后来 C++ 哲学的来源: "Don't pay for what you don't use."(不为你不用的东西付费) "As fast as C, as expressive as Simula."(与 C 一样快,与 Simula 一样有表现力)
# 2.2 "C with Classes" 阶段
1979-1983 年,Stroustrup 给 C 添加了:
- 类(class)
- 派生类(derived class)
- 强类型(strong typing)
- 内联函数(inline functions)
- 默认参数(default arguments)
最初这门语言叫 "C with Classes",1983 年才正式命名为 C++(来自 C 语言的递增运算符 ++,意为"C 的后继版本")。
# 2.3 1985 年 The C++ Programming Language 第一版
1985 年,Stroustrup 出版了 《The C++ Programming Language》第一版——这本书是 C++ 的第一份"非正式标准"。同年发布的 C++ 编译器 Cfront 1.0,本质上是把 C++ 翻译成 C 再编译。
┌─────────┐ Cfront ┌─────────┐ C 编译器 ┌──────┐
.cpp │ C++ 源 │ ───────▶ │ C 中间 │ ────────▶ │ 二进制│
└─────────┘ └─────────┘ └──────┘
2
3
这种"翻译式"实现也注定了 C++ 必须长期兼容 C——这是 C++ 后来一切设计取舍的根本约束。
# 03.标准化时代(1998-2003)
# 3.1 C++98:第一个 ISO 标准
经过 9 年 ISO 标准化拉锯,1998 年 C++98 正式发布。这是 C++ 历史上第一个真正的"标准"。
C++98 的标志性贡献:
- ✅ STL(Standard Template Library) 由 Alexander Stepanov 设计,纳入标准库
- ✅
std::string/std::vector/std::map等常用容器 - ✅ 模板(templates)正式入标
- ✅ 异常处理(try / catch / throw)
- ✅ 命名空间(namespace),所有标准库符号搬进
std:: - ✅ RTTI(运行时类型识别,
typeid/dynamic_cast) - ✅ 四种 C++ 风格类型转换(
static_cast/dynamic_cast/const_cast/reinterpret_cast)
# 3.2 C++03:稳定与小修小补
2003 年 C++03 是一次"维护性发布"——只是修了 C++98 的几十个缺陷(DR, Defect Reports),几乎没有新特性。
从读者角度:C++98 和 C++03 可视为同一版本,写代码时叫"C++98"或"C++03"都对。
# 3.3 这个时代的写法长什么样
// C++98/03 典型代码——这是很多老项目里你会看到的风格
#include <iostream>
#include <vector>
#include <string>
int main() {
std::vector<std::string> names;
names.push_back("Alice");
names.push_back("Bob");
// 没有 auto,迭代器类型必须写全
for (std::vector<std::string>::iterator it = names.begin();
it != names.end(); ++it) {
std::cout << *it << std::endl;
}
// 没有 nullptr,只能用 0 或 NULL
int* p = NULL;
// 没有 std::shared_ptr / std::unique_ptr(除非用 boost::)
int* arr = new int[100];
delete[] arr; // 一定要记得,否则泄漏
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
每一行都"能用、能跑",但每一行都比 C++17 啰嗦 2-3 倍。
# 04.停滞的十年(2003-2011)
# 4.1 委员会的"C++0x"承诺
C++ 标准委员会原本计划 C++0x(x 表示个位数年份)在 2007 或 2009 年发布。但因为 Concepts 提案过于复杂、设计推翻多次,迟迟无法落地。
最终 Concepts 被砍掉(推迟到 12 年后的 C++20),新标准延期到 2011 年。
业内黑色幽默:"C++0x"中的 x 最终变成了 16 进制 0xb(11)。
# 4.2 Boost 库扛起社区创新
在 2003-2011 这八年里,C++ 标准没动,但社区没停——Boost 库成为事实上的"现代 C++ 实验场":
| Boost 中的库 | 后来进入了 C++ 的哪个版本 |
|---|---|
boost::shared_ptr / weak_ptr | C++11 标准库 |
boost::function / bind | C++11 标准库 |
boost::thread | C++11 标准库 |
boost::tuple / array | C++11 标准库 |
boost::any / optional / variant | C++17 标准库 |
boost::filesystem | C++17 标准库 |
boost::ranges | C++20 标准库 |
学习提示:Boost 至今仍是"将来标准库"的预演场,遇到一个想要的功能但 STL 还没有,先去 Boost 找。
# 4.3 此时 Java、C#、Python 已经把 C++ 甩在身后
2003-2011 年是其他语言的爆发期:
- Java 5(2004)引入泛型、注解、
for-each - C# 3.0(2007)引入 LINQ、Lambda
- Python 2.5/2.6/2.7 大量改进
- Ruby on Rails 火爆,让 Web 开发离开 C++
C++ 一度被认为是"夕阳语言"——直到 C++11 横空出世。
# 05.现代 C++ 的开端:C++11
# 5.1 一次"看似新语言"的升级
2011 年 9 月,C++11 ISO 标准发布。Bjarne Stroustrup 评价:
"C++11 feels like a new language." (C++11 让 C++ 像一门新语言。)
它带来的特性数量之多、影响之深远,至今每一行现代 C++ 代码都离不开 C++11。
# 5.2 C++11 的十大革命性特性
| # | 特性 | 一句话价值 |
|---|---|---|
| 1 | auto 类型推导 | 告别冗长的 std::vector<std::string>::iterator |
| 2 | nullptr | 修复 NULL、0 在重载和模板中的歧义 |
| 3 | 范围 for 循环 | for (auto& x : container) |
| 4 | Lambda 表达式 | 让函数式编程进入 C++ |
| 5 | 右值引用 + 移动语义 | 性能跃升,是后来一切高性能 C++ 的基石 |
| 6 | 智能指针(unique_ptr / shared_ptr / weak_ptr) | RAII 终于"标配化" |
| 7 | std::thread / mutex / atomic | 标准库内置多线程 |
| 8 | 统一初始化 {} | std::vector<int> v{1, 2, 3}; |
| 9 | 强类型枚举 enum class | 命名空间隔离 + 不能隐式转 int |
| 10 | constexpr | 编译期计算开始进入主流 |
还有一些重要但不那么"显眼"的:
override/final、变长模板、初始化列表、std::function、std::tuple、统一返回类型推导(C++14 才完全完成)……
# 5.3 老 C++ 与现代 C++ 的写法对比
// ❌ C++98/03 写法
std::vector<std::string> v;
v.push_back("Alice");
for (std::vector<std::string>::iterator it = v.begin();
it != v.end(); ++it) {
std::cout << *it << std::endl;
}
// ✅ C++11+ 写法
std::vector<std::string> v{"Alice", "Bob", "Carol"};
for (const auto& name : v) {
std::cout << name << '\n';
}
2
3
4
5
6
7
8
9
10
11
12
13
代码量减半,可读性翻倍——而且性能更好(移动语义)。
# 06.稳定演进期:C++14 / C++17
# 6.1 C++14:补丁式更新
2014 年 8 月发布。它是"小步快跑"——大多数特性是 C++11 的 bug 修复 / 完善:
auto用作函数返回类型推导(C++11 时只能用尾置语法)- 泛型 Lambda:
[](auto x) { ... } std::make_unique<T>(...)(C++11 漏写了!)constexpr函数大幅放宽限制- 二进制字面量:
0b1010
# 6.2 C++17:使用更舒适的 C++
2017 年 12 月发布。对工程师最实用的一次升级:
| 特性 | 用一句话说价值 |
|---|---|
结构化绑定 auto [a, b] = pair; | 拆 pair、tuple 不再痛苦 |
if / switch 初始化语句 if (auto v = f(); v > 0) | 减少作用域污染 |
if constexpr | 模板里的"编译期分支",源码更易读 |
std::optional<T> | "可能没有值"的标准表达 |
std::variant<T1, T2, ...> | 类型安全的 union |
std::string_view | 零拷贝字符串视图 |
std::filesystem | 跨平台文件系统操作 |
折叠表达式 (args + ...) | 变长模板写起来不再恐怖 |
嵌套命名空间 namespace a::b::c {} | 一行解决三层命名空间 |
| 拷贝省略(保证的 RVO) | 返回值优化进入语言层面 |
本书将 C++17 作为"基线"——如果一段代码没标版本,就是 C++17。
# 07.再次革命:C++20
# 7.1 四大支柱:Concepts / Ranges / Modules / Coroutines
2020 年 12 月发布的 C++20,深度堪比 C++11:
| 支柱 | 解决了什么问题 |
|---|---|
| Concepts | 模板编程错误信息从 1000 行降到 5 行;约束变得可读 |
| Ranges | STL 算法可以"链式调用",告别迭代器对 |
| Modules | 头文件 #include 终于有了替代方案,编译时间大幅下降 |
| Coroutines | 异步代码可以同步写法,与 async/await 类似 |
# 7.2 太空船运算符 <=> 与 std::format
// C++20 之前:要让一个类支持比较,要写 6 个运算符
bool operator==(const A&) const;
bool operator!=(const A&) const;
bool operator<(const A&) const;
bool operator<=(const A&) const;
bool operator>(const A&) const;
bool operator>=(const A&) const;
// C++20 之后:一个 <=> 全搞定
struct A {
int x;
auto operator<=>(const A&) const = default; // 默认按字段顺序比较
};
2
3
4
5
6
7
8
9
10
11
12
13
std::format 终于让 C++ 有了 Python 那样的 "Hello, {}!".format(name) 风格:
std::cout << std::format("Hello, {}! You are {} years old.\n", name, age);
# 7.3 C++20 编译器实现进度的现实
C++20 是个"标准发布了,编译器追了两年才追完"的版本。直到 2023 年中,三大编译器才基本完整支持 C++20:
| 编译器 | 最低完整支持版本 |
|---|---|
| GCC | 13 |
| Clang | 16 |
| MSVC(VS 2022) | 17.5+ |
实战建议:写 C++20 代码前,先 g++ --version 确认编译器版本。
# 08.最新版本:C++23 / C++26 展望
# 8.1 C++23 的关键新特性
2023 年 11 月正式发布。重点:
std::expected<T, E>—— 比异常更轻量的错误处理std::print/std::println——cout终于不用再写<< endl了if consteval—— 编译期与运行期分支- deducing this("Explicit object parameter") —— Lambda 与成员函数统一
- 多维下标
arr[i, j]—— 矩阵操作更自然 std::flat_map/std::flat_set—— 缓存友好的有序容器
# 8.2 C++26 路线图速览
预计 2026 年发布。已确定纳入的方向:
- 反射(Reflection) —— 编译期遍历类型、生成代码
- 网络库(Networking TS) —— 标准库内置 socket / TLS
- 执行器(Executors) —— 协程、线程池的统一抽象
- 合约(Contracts) —— 前置条件 / 后置条件 / 不变量
学习节奏建议:先把 C++17 用熟,再尝试 C++20,C++23/26 可观望。
# 09.如何在项目中选择 C++ 版本
# 9.1 不同版本的编译器最低要求
| C++ 版本 | GCC | Clang | MSVC |
|---|---|---|---|
| C++11 | 4.8.1 | 3.3 | VS 2015 |
| C++14 | 6.1 | 3.4 | VS 2017 |
| C++17 | 7.1 | 5.0 | VS 2017 15.7 |
| C++20 | 13 | 16 | VS 2022 17.5 |
| C++23 | 14(部分) | 18(部分) | VS 2022 17.10(部分) |
# 9.2 工业界的"实际使用版本"分布
根据 ISO C++ 委员会 2023 年 Annual Survey 与 JetBrains State of C++ 报告:
C++17 (54%) ████████████████████████████████████████████████████████
C++20 (24%) ████████████████████████
C++14 (12%) ████████████
C++11 (8%) ████████
其他 (2%) ██
2
3
4
5
结论:2026 年的今天,写新项目用 C++17 是最稳妥的选择,C++20 在新项目中比例正在快速上升。
# 9.3 本书的版本基线选择
| 卷 | 基线 | 选择理由 |
|---|---|---|
| 卷一 语法卷 | C++17 | 编译器全平台支持稳定 |
| 卷二 工程卷 | C++17 + 关键 C++20 | CMake 模板、单元测试、并发都基于此 |
| 卷三 底层卷 | C++17 / 20 / 23 | 底层原理需要展示完整演进 |
| 卷四 实战卷 | C++17 | 与生产环境一致 |
所有代码示例默认能在以下三套环境编译通过:
GCC 11.4 + libstdc++ (Ubuntu 22.04)
Clang 14 + libc++ (macOS 13+)
MSVC 19.32 + STL (Visual Studio 2022 17.2+)
2
3
# 10.本章新手陷阱 Top 5
这是贯穿本卷每章末尾的固定栏目——用最短的话告诉你"哪些代码能编译过、能跑起来、但是错的"。
# 陷阱 1:在简历写"精通 C++",但说不出 C++17 的特性
错误:写"精通 C++",被问"std::optional 怎么用?" 卡壳。
正确:写"熟悉 C++17",并能脱口说出 5-8 个 C++17 特性(结构化绑定、if-init、std::optional、std::filesystem……)。
# 陷阱 2:把 using namespace std; 写在头文件里
错误:
// my_header.h
#include <iostream>
using namespace std; // ❌ 任何包含此头文件的源文件都被污染
2
3
正确:仅在 .cpp 文件 / 函数内部使用,头文件中永不使用 using namespace。
# 陷阱 3:用 NULL 而不是 nullptr
错误:
void f(int);
void f(char*);
f(NULL); // ❌ 调用 f(int),因为 NULL 实际上是 0
2
3
正确:C++11 起统一用 nullptr,类型为 std::nullptr_t,专门修复了这个歧义。
# 陷阱 4:还在用 typedef 而不是 using
错误:
typedef std::map<std::string, std::vector<int>>::iterator iter; // ❌ 写得反人类
正确:
using iter = std::map<std::string, std::vector<int>>::iterator; // ✅ 同时支持模板别名
# 陷阱 5:以为"C++ = C 加上类"
错误:把 malloc / free / 裸数组 / printf 当主流写法。
正确:现代 C++ 是完全不同的语言——值语义、RAII、容器、智能指针、<< 流——把"我会 C"暂时放下,把 C++ 当新语言重学。
# 11.思考题
- C++98 和 C++03 在语言层面有差别吗?为什么大部分书把它们当作"同一版本"来讲?
- C++11 引入
nullptr的根本原因是什么?写一段代码,演示NULL在重载场景下的歧义。 - C++17 的
std::filesystem在 C++14 时代你会用什么替代? - 为什么 Concepts 和 Modules 等了将近 20 年才进标准?
- 假如你正在维护一个用 C++03 写了十年的金融交易系统,你会建议升级到 C++17 还是 C++20?说明理由。
std::optional<T>解决了什么问题?没有它的时候,C++ 程序员怎么表达"可能没有值"?- 用一句话告诉非 C++ 程序员"C++11 跟 C++98 的最大区别是什么"。
- 查一下你机器上的 GCC / Clang 版本,能编译 C++ 几?
- Boost 库与 C++ 标准库是什么关系?什么时候应该用 Boost?
- 假如你要选一门"未来 5 年最值得深入"的语言,C++ 还是 Rust?请给出至少 3 条对比理由。
# 12.推荐阅读
- ➡ 下一章:第 2 章 基础语法与第一个程序
- ➡ 跳读:第 18 章 C++11 至 C++23 关键特性速览图谱
- 📕 The Design and Evolution of C++ by Bjarne Stroustrup(C++ 之父亲自写的设计史)
- 📕 A Tour of C++ (3rd ed.) by Bjarne Stroustrup(200 页讲完 C++17/20 全貌)
- 🔗 ISO C++ 官方:https://isocpp.org
- 🔗 cppreference 中文:https://zh.cppreference.com
- 🔗 Annual ISO C++ Developer Survey(每年发布的工业界 C++ 用法统计)