第一章:C语言回顾与C++初探
1.1 从C到C++的演进:一场有预谋的升级
说实话,C语言是个好东西。我当年刚入行时,团队里全是C语言的死忠粉。大家觉得C够快、够底层、够自由。但做着做着就发现问题了——代码规模一大,管理起来真头疼。
C++的出现,说白了就是给C语言穿上了铠甲。它保留了C的全部战斗力,又加了一堆新武器。你想想看,一个项目从几千行膨胀到几十万行,光靠C的struct和函数指针,维护成本会直线飙升。
我在项目中遇到过最典型的场景:一个嵌入式通信协议栈,用C写了三年,每次加新功能都要改一堆全局变量和回调函数。后来用C++重构,把状态机封装成类,把回调改成虚函数——嗯,世界清净了。
C++到底多了什么?我列个表给你看:
| 特性 | C语言 | C++ |
|---|---|---|
| 编程范式 | 面向过程 | 面向过程 + 面向对象 + 泛型 |
| 数据封装 | struct(仅有数据) | class(数据+方法+访问控制) |
| 代码复用 | 函数 + 宏 | 继承 + 模板 + 多态 |
| 错误处理 | 返回值 + errno | 异常机制(try/catch) |
| 内存管理 | malloc/free | new/delete + RAII |
看到没?C++不是要取代C,而是给C开发者一条更宽敞的路。我个人习惯把C++看作「C语言的超集」——你写的C代码,在C++编译器下基本都能跑。但反过来,C++的新特性,C一个都用不了。
核心观点:C++是C的进化,不是革命。它保留了C的性能优势,同时引入了工程化所需的结构化能力。
1.2 第一个C++程序:Hello World的变与不变
来,先写个最经典的例子。你肯定写过C语言的Hello World,看看C++版本有什么不同:
#include <iostream> // C++的标准输入输出头文件
using namespace std; // 使用标准命名空间
int main() {
cout << "Hello, World!" << endl;
return 0;
}
是不是感觉有点眼熟?main函数的签名没变,return 0也没变。但注意看:
#include <iostream>代替了#include <stdio.h>cout代替了printfendl代替了\n- 多了个
using namespace std;
我曾经见过新手直接写 #include <iostream.h>——这是老古董的写法,现在早就不用了。记住,标准C++的头文件没有 .h 后缀。
小技巧:如果你不想写 using namespace std;,也可以每次手动加 std:: 前缀。比如 std::cout << "Hello" << std::endl;。我个人建议小项目用using,大项目还是加前缀更清晰。
1.3 命名空间:为什么C++需要这个玩意儿?
你写C语言时有没有遇到过这种尴尬:两个第三方库都定义了一个叫 init() 的函数,链接时直接报重定义错误。我当时在一个通信项目里就踩过这个坑——A库的 init() 初始化硬件,B库的 init() 初始化协议栈,结果死活链接不过去。
C++的命名空间就是来解决这个问题的。它相当于给代码加了个「姓氏」:
namespace Hardware {
void init() {
// 初始化硬件
}
}
namespace Protocol {
void init() {
// 初始化协议栈
}
}
int main() {
Hardware::init(); // 调用硬件初始化
Protocol::init(); // 调用协议初始化
return 0;
}
你看,同名函数,各叫各的,互不干扰。命名空间的核心作用就两个:
- 避免命名冲突——不同模块的同名实体可以共存
- 组织代码逻辑——把相关的函数、类、变量放在一起
命名空间还可以嵌套:
namespace Company {
namespace Project {
namespace Module {
void doSomething();
}
}
}
// 调用时:Company::Project::Module::doSomething();
是不是有点长?你可以用 using 来偷懒:
using Company::Project::Module::doSomething;
doSomething(); // 直接调用
注意:不要在头文件里写 using namespace std;!我曾经在一个团队里看到有人这么干,结果整个项目组都被牵连——所有包含这个头文件的代码都莫名其妙地引入了std命名空间,排查了半天。头文件里请老老实实写全名。
1.4 输入输出流:告别printf的繁琐
C语言的 printf 和 scanf 用起来其实挺累的——你要记住各种格式符:%d、%f、%s、%x……写错一个格式符,轻则输出乱码,重则程序崩溃。
C++的输入输出流(iostream)就友好多了。它用 << 和 >> 操作符,自动识别类型:
#include <iostream>
using namespace std;
int main() {
int age = 25;
double salary = 12345.67;
string name = "张三";
// 输出:自动识别类型,不用写格式符
cout << "姓名:" << name << endl;
cout << "年龄:" << age << endl;
cout << "薪资:" << salary << endl;
// 输入:同样自动识别
int inputAge;
cout << "请输入你的年龄:";
cin >> inputAge;
cout << "你输入的年龄是:" << inputAge << endl;
return 0;
}
为什么会这样?因为C++的 cout 和 cin 是对象,它们重载了 << 和 >> 操作符。每种基本类型都有对应的重载版本,编译器自动匹配。
我刚开始用C++时,觉得 cout << a << b << c 这种链式写法很别扭。用习惯了才发现,这比 printf("%d %f %s", a, b, c) 直观多了——至少你不用数参数个数对不对得上。
对比总结:
| 功能 | C语言 | C++ |
|---|---|---|
| 输出整数 | printf("%d", x); | cout << x; |
| 输出浮点数 | printf("%.2f", x); | cout << fixed << setprecision(2) << x; |
| 输入整数 | scanf("%d", &x); | cin >> x; |
| 输入字符串 | scanf("%s", buf); | cin >> str; 或 getline(cin, str); |
注意看,C++的输入不需要取地址符 &。因为 cin >> x 内部是通过引用传递的,自动拿到了变量的地址。少写一个符号,少犯一个错。
避坑指南:我曾经在项目里用 cin >> str 读取用户输入的姓名,结果用户输入了「张三 李四」——中间有空格,程序只读到了「张三」。因为 cin >> 遇到空格就停了。要读取一整行,请用 getline(cin, str)。
知识体系总览
下面这张图帮你理清本章的核心脉络:
这张图把本章四个核心知识点串起来了。从C到C++的演进是背景,第一个程序是入门,命名空间解决工程痛点,输入输出流提升开发效率。每一步都有它的道理。
好了,第一章的内容就到这里。记住,C++不是一门新语言,它是C语言的进化版。你已有的C语言功底不会白费,反而会让你更快理解C++的设计哲学。