C++ 简介

c++基础 › C++ 简介 (第 1 章)
文章工具

C++ 是一门「在编译期就把类型和错误管住」的语言:它让你既写出高级的抽象,又能精确控制内存与性能。

学完你能做什么

  • 用自己的话说清「静态类型、编译式、多范式」三个词的含义,并各举出一条实际好处。
  • 独立编译运行一个用到 std::cout 和 std::vector 的程序,能大致看懂报错指向哪里。
  • 写出一个「数据私有、只留接口」的最小类,说明封装解决了什么问题。
  • 判断「这个 C 程序能不能直接被 C++ 编译」,并说出理由,而不是笼统地说「C 是 C++ 的子集」。
先建立直觉:既懂图纸,也懂砖头(示意图)
图:先建立直觉:既懂图纸,也懂砖头
阶段做什么常见命令产物
预处理展开 #include 与宏,处理条件编译g++ -E hello.cpp展开后的源文本
编译语法语义分析、类型检查,生成汇编g++ -S hello.cpp汇编 .s
汇编把汇编翻译成机器码g++ -c hello.cpp目标文件 .o
链接与其他目标码、标准库合并、解析符号g++ hello.o -o hello可执行文件

要点:#include 只是文本替换,包含越多、解析越久;链接阶段才把 std::cout 这类符号补上。

先建立直觉:既懂图纸,也懂砖头

写程序要同时做两件事:表达「我要做什么」,以及安排「东西放在哪、占多少空间」。

多数语言偏一边:脚本语言偏前者,机器码偏后者。C++ 两头都要抓,所以常被称作中级语言——不是「水平中等」,而是「介于高底层之间」。

它的办法是:所有「高级」的东西(类、模板)都在编译期被翻译掉,运行时几乎看不到痕迹;真需要抠内存时,又能用指针直接下手。这个思路叫零开销抽象:你不用的东西,不该让你付出代价。

从最简单的用法开始

先写一个只做一件事的程序:把变量打印出来。

C++ 示例

▶ 在线运行:改一改再点“运行”试试(本站沙箱执行,登录后可运行)。

存成 hello.cpp,再编译运行:

C++ 片段需补全 main() 函数才能运行在实训台打开 →
g++ -std=c++17 -Wall hello.cpp -o hello
./hello

预期输出:age = 20

逐句看:#include 是「把另一个文件的内容搬到这里」;int main() 是程序入口,返回 int 表示退出状态;int age = 20; 声明了一个变量,类型是 int,意思是「只能装整数」。

再往下看:为什么它快、为什么它严

一句 #include 背后是三步翻译

从 hello.cpp 到可执行文件,标准规定的过程大致是:预处理(展开 #include 和宏)→ 编译(生成汇编与目标码)→ 链接(把目标码和标准库拼起来)。

所以 #include 只是文本替换。你包含 <iostream>,编译器就得把所有声明解析一遍——这正是 C++ 编译偏慢的原因之一。这是实现层面的观察,不是某条规定。

静态类型:把检查提前到编译期

「静态类型」指变量的类型在编译时就已经确定。好处有两个:错误在编译期就被拦住,不用等程序跑起来才崩;编译器知道每个东西的类型和大小,就能直接生成针对该类型的机器指令,不必在运行时再查「这是什么类型、该怎么加」。

这就是「编译时类型检查」比「运行时类型检查」快的原因。语言规则要求类型在编译期确定;实现细节是各家编译器据此生成什么指令。代价是灵活性:类型不对就得改代码,而不能运行时临时决定。

三大块与多范式

标准 C++ 可分为:核心语言(变量、类型、函数、类这些积木)、标准库(<iostream>、<string>、<vector> 等现成工具),以及常被单独提起的 STL。严格说 STL 早已并入标准库,并列只是口语习惯。要分清:哪部分是语言规则,哪部分是库。

C++ 同时支持面向过程、面向对象、泛型三种风格。面向对象常提四件事:封装(数据藏起来,只留接口)、抽象(只暴露必要概念)、继承(复用并扩展已有类型)、多态(同一调用、不同实现)。

对比

维度CC++
类型规则较宽松(如 void* 可隐式转换)更严格,常需显式转换
抽象工具主要靠函数和结构体类、模板、命名空间等
标准库较小大得多,含容器与算法
典型场景系统与嵌入式底层底层到大型应用都覆盖

口诀:C 给你自由,C++ 给自由加类型;编译期多做判断,运行时少花功夫。

实战:一个会算平均分的 Student

C++ 示例

预期输出:2 students, average = 85

看点:name_、score_ 放在 private 里,外部只能通过 score() 读——这就是封装,日后想改内部表示不会影响调用者。std::vector<Student> 是泛型容器,同一份代码能装任意类型。范围 for 加 const Student& 表示「只读,且不复制」。

维度有符号 int无符号 std::size_t(v.size() 的返回类型)
取值范围约 ±21 亿,可为负只有非负,上限约为前者两倍
与其他类型混算遇到无符号操作数会被转成无符号会「吞掉」有符号操作数,负数变成巨大正数
典型坑total / v.size() 结果可能反常循环 for (unsigned i = n-1; i >= 0; --i) 永不结束
推荐写法先显式转换再运算,如 total / static_cast<int>(v.size());并开启 -Wall 让编译器提醒

口诀:有符号遇上无符号,小的先被抬成大的;拿不准就显式转换。

易错点(先错后对)

错法一:写 int avg = total / v.size();。v.size() 返回的是无符号类型,与 int 混用会把 total 也转成无符号:一旦 total 为负,结果会变成一个巨大的数,-Wall 也会警告。正确做法是显式转换:total / static_cast<int>(v.size())。

错法二:「C 是 C++ 的子集,所以任何 C 程序都能编过」。反例一:int n = 5; int a[n];(变长数组)在 C99 合法,但在标准 C++ 中不合法,应改用 std::vector<int> a(n);。反例二:void* p = &x; int* q = p; 在 C 中可隐式转换,C++ 必须写 static_cast<int*>(p)。原因是 C++ 的类型规则更严。

再深入一点:标准版本与未定义行为

C++ 由 ISO 标准化,版本按年份命名:C++98、C++03、C++11、C++14、C++17、C++20。每次更新都在扩充核心语言和标准库。

标准只规定「应该发生什么」,具体怎么实现由编译器决定。因此同一份代码在不同编译器、不同优化等级下表现可能不同,尤其是未定义行为:越界访问、读未初始化变量、有符号整数溢出等。这类代码不是「碰巧结果对就行」,而是整段程序的行为都没有保证——优化器可能做出你完全想不到的事。

自测练习

  1. 什么是静态类型?为什么「编译时检查类型」能让程序跑得更快?
  2. 从 .cpp 到可执行文件经过哪几个阶段?为什么包含大文件会让编译变慢?
  3. 下面两行各有什么问题:int n = 5; int a[n]; 和 total / v.size()?
参考答案

1. 静态类型指变量类型在编译期确定。编译器因此能在编译阶段发现类型错误,并且知道每个对象的类型与大小,可直接生成针对该类型的指令,省去运行时的类型判断与分派,所以更快。

2. 预处理(展开 #include 和宏)→ 编译(生成汇编与目标码)→ 链接(合并标准库、生成可执行文件)。#include 是文本替换,包含越多,编译器要解析的声明越多,编译越慢。

3. int a[n] 是变长数组,n 不是常量,标准 C++ 不允许,应改用 std::vector<int> a(n);。total / v.size() 是有符号与无符号混用,会触发隐式转换,应写 static_cast<int>(v.size())。

一句话记住

类型在编译期定下来,抽象在编译期消掉,代价按需支付——这就是 C++。

延伸阅读

⚠️ 版权声明

本文为免费文章,欢迎转载。转载请注明出处:一木科技(https://www.pingquan.vip/2026/09/24/cpp-intro/),并保留原文链接。