第一章: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 代替了 printf
  • endl 代替了 \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++初探 1. 从C到C++的演进 保留C的全部性能 新增面向对象特性 更好的工程化支持 2. 第一个C++程序 iostream 替代 stdio.h 3. 命名空间 避免命名冲突 4. 输入输出流 cout 输出(类型安全) cin 输入(无需取地址) 链式操作 << / >>

这张图把本章四个核心知识点串起来了。从C到C++的演进是背景,第一个程序是入门,命名空间解决工程痛点,输入输出流提升开发效率。每一步都有它的道理。

好了,第一章的内容就到这里。记住,C++不是一门新语言,它是C语言的进化版。你已有的C语言功底不会白费,反而会让你更快理解C++的设计哲学。

可可精品资料库