C++ 四十年演进史与核心概念解析
结束了 C 语言的学习,我们开始探索 C++ 这门更强大的编程语言。C++ 在 C 语言的基础上发展而来,既保留了其高性能特性,又增加了面向对象和泛型编程等现代化功能。经过数十年发展,C++ 通过命名空间解决了标识符冲突问题,提供了丰富的标准模板库,C++11 及后续标准更带来了革命性改进。
一、波澜壮阔的 C++'发家'历史
纵观 C++ 的发展历程,大致可以概括为以下几个关键节点:
1. C with Classes (1979-1983) - 起源
**'C++之父'**是本贾尼·斯特劳斯特卢普(Bjarne Stroustrup)。
开创初衷: 在 C 语言的高效和底层控制能力基础上,通过增加面向对象和泛型编程等机制,来应对大规模软件工程的复杂性。
关键特性: 主要引入了类、基本继承、内联函数和访问控制等核心概念。
2. 早期发展:C++的"++"从何来 (1983-1989)
- 正式命名: 1983 年,语言正式更名为 C++。"++"是 C 语言的自增运算符,象征着对 C 语言的超越。
- 语言丰富特性: 增加了虚函数、函数和运算符重载、引用、常量等,奠定了其特色功能。
- 走向世界: 1985 年,本贾尼发布经典著作《The C++ Programming Language》,同年首个商业 C++ 编译器 C Front 发布,推动了语言的普及。
3. 标准化与成熟 (1990-1998)
- 标准启动: 为避免不同编译器可能导致的分裂,ANSI 和 ISO 于 1990 年联合开始了 C++ 的标准化进程。
- STL 的融合: 标准模板库 (STL) 被纳入标准草案。STL 提供了泛型的容器、迭代器和算法,极大提升了代码的复用性和表现力。
- 首个国际标准: C++98 于 1998 年正式发布。它统一了语言规范,确立了模板、异常处理等现代特性,这标志着 C++ 成为一个成熟、稳定的工业级语言。
4. 现代化浪潮(2011-至今)
- 里程碑: C++11,被视为现代 C++ 的开端,是一次翻天覆地的更新。
- 持续演化:
- C++14:对 C++11 的小幅度增强和缺陷修复,被称为'完整版的 C++11';
- C++17:引入更多的实用特性,如结构化绑定、
std::filesystem、std::variant等; - C++20:C++ 的一次飞跃,引进了模板、概念、协程等改变编程范式的强大特性;
- C++23:对 C++20 的进一步完善,增加了更多的标准库支持和语言特性。

二、推荐学习资源与书籍
在学习过程中,选择合适的参考资料至关重要。
参考网站
- https://legacy.cplusplus.com/reference/ 注意,这个网站不是 C++ 的官方网站,已停止更新,其中 C++ 标准只更新到了 C++11。但网站内容的呈现是以头文件的形式,比较容易使用。
- https://zh.cppreference.com/w/cpp
- https://en.cppreference.com/w/ 第 2、3 两个网站是当前 C++ 官方维护的网站。一个是中文版、一个是英文版,相较于第一个网站内容更专业。(遗憾的是,中文版网站目前失效,建议优先使用英文版)
书籍推荐
- 《C++ Primer》 这是一本系统讲解 C++ 语法的权威著作,被誉为 C++ 程序员的语法宝典。适合编程的各个阶段阅读:学习初期可作为入门引导,虽然大部分内容抽象,能看懂多少算多少;中后期则是作为语法字典,随时查阅不懂的语法,提升编程能力。
- 《STL 源码剖析》 由侯捷老师编著的经典之作,深入剖析了 C++ 的标准模板库和源码实现,从底层角度揭示 STL 的设计精髓。阅读这本书能让人体会到工程级别的代码封装与设计思想。建议在有了一定的 C++ 基础后再阅读,以拓宽视野。
- 《Effective C++》 同样由侯捷老师翻译的经典之作。在 C++ 社区有这样一句话:'C++程序员分为读过这本书的和没有读过的'。书中提炼了 55 条高效使用 C++ 的使用准则,建议在学习的中后期再翻阅。工作 1~2 年后重新阅读,结合工作经验,会有额外的收获。
三、梦开始的地方:C++ 的第一个程序
最开始学习 C 语言,我们是从 hello world 启程:
#include <stdio.h>
int main() {
printf("Hello World\n");
return 0;
}
那么也来试着使用 C++ 输出 hello world 吧。
#include <iostream>
using namespace std;
int main() {
cout << "Hello World" << endl;
cout << "Hello World" << endl;
return 0;
}
虽然 C++ 兼容 C 语言的大部分语法,C 语言形式的 hello world 仍然可以运行,但是 C++ 作为 C 语言的升级版本,有着自己的一套输入输出体系。
在上面代码中,像
std、cout、namespace现在肯定是不懂的,但别急,很快学到。
1. '我'作先锋:namespace 的意义
要知道,C/C++ 中存在着大量的变量、函数,当然还有后面要学习的类,这些都是需要进行命名的并且作用在全局作用域中,势必会有一些名称冲突。
关键字 namespace 就是来解决这个问题的:利用命名空间对标识符的名称进行本地化,很好地避免了命名冲突。
提一嘴:命名冲突在 C 语言的程序中非常普遍
#include <stdio.h>
#include <stdlib.h>
// 命名冲突
int rand = 100; // 全局变量
int main() {
printf("%d\n", rand);
return 0;
}
报错: 错误 C2365 'rand' : 重定义;以前的定义是'函数'。
这是因为我们包含了头文件 <stdlib.h>,头文件有函数 rand,全局变量 rand 命名就冲突了。
2. namespace 的定义
- 关键字
namespace用来定义命名空间,后面跟名称,再加一对{ }。{ }中放置命名空间的成员,空间可以定义变量、函数、类型……
// 命名空间使用
#include <stdio.h>
#include <stdlib.h>
// ns 是命名空间的名字,一般开发中是用项目名字做命名空间名。
namespace ns {
// 命名空间中可以定义变量/函数/类型
int rand = 10;
int Add(int left, int right) {
return left + right;
}
struct Node {
struct Node* next;
int val;
};
}
int main() {
// 默认访问的是全局的 rand 函数指针
printf("%p\n", rand);
// 指定 ns 命名空间中的 rand
printf("%d\n", ns::rand);
return 0;
}
注意:
- 命名空间的
{ }后面没有分号;。 - 编译器默认查找规则是先局部再全局。
- 访问命名空间成员用到了域作用限制符
::,用来指定作用域。
namespace实质上是定义出一个域,并且与全局作用域各自独立。不同的域可以定义相同的变量,那么命名空间的rand就不冲突了。- 在 C++,有函数局部域、全局域、命名空间域、类域。作用域确定了编译器如何查找一个标识符(变量、函数、类型)的声明、出处。 经过域的隔离,命名冲突就解决了。局部域、全局域会影响编译查找逻辑,还会影响变量的生命周期,但是命名空间域、类域不会。
namespace ns {
int a = 1;
}
int a = 2;
int main() {
int a = 3;
// 访问局部域
printf("%d\n", a);
// 访问全局域,域作用限制符左侧空白表示:全局域
printf("%d\n", ::a);
// 访问命名空间域
printf("%d\n", ns::a);
return 0;
}
- namespace 只能定义在全局,可以嵌套定义。
// 命名空间可以嵌套
namespace ns {
namespace inner {
int rand = 1;
int Add(int left, int right) {
return left + right;
}
}
namespace outer {
int rand = 2;
int Add(int left, int right) {
return (left + right) * 10;
}
}
}
int main() {
printf("%d\n", ns::inner::rand);
printf("%d\n", ns::outer::rand);
return 0;
}
- 工程中多个文件定义的同名
namespace,会默认为一个(合并)。 - C++ 标准库都放在
std(standard) 的命名空间中。
3. 命名空间的使用
编译查找一个变量的声明/定义,默认在局部或者全局找,不会到命名空间域中查找。所以有 3 种使用命名空间中的成员的方法:
- 指定命名空间访问,在大型项目中推荐,虽然有点麻烦。
using将命名空间的某个成员暴露在全局中,在项目中经常要访问并且不冲突的成员推荐。- 将空间中全部成员暴露在全局中,但是风险大,日常的练习可以,项目中不推荐。
- 指定命名空间访问:
#include <stdio.h>
namespace my_ns {
int a = 0;
int b = 1;
}
// 指定命名空间
using my_ns::a;
int main() {
int b = 2;
printf("%d\n", my_ns::b);
return 0;
}
- 命名空间中指定成员展开:
#include <stdio.h>
namespace my_ns {
int a = 0;
int b = 1;
}
// 命名空间中指定成员展开
using my_ns::a;
int main() {
printf("%d\n", a);
return 0;
}
- 展开全部成员:
#include <stdio.h>
namespace my_ns {
int a = 0;
int b = 1;
}
// 展开全部
using namespace my_ns;
int main() {
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
总结
C++ 并非要取代 C 语言,而是在其基础上进行全面升级和扩展。它完整保留了 C 语言的高效性和底层控制能力,同时引入了面向对象编程、泛型编程等现代化特性,让我们能够应对更复杂的软件开发需求。 C++ 的学习是一个循序渐进的过程。建议从基础语法开始,逐步深入理解面向对象思想,最后掌握模板和现代 C++ 特性。多动手实践,结合实际项目,才能真正领略 C++ 的强大威力。


