《C++ Primer 第五版》是 C++ 领域的经典教材,全面覆盖了 C++11 标准的核心特性,兼顾语法细节与编程实践,既适合初学者入门,也适合有经验开发者查漏补缺。

以下从基础概念、核心特性、容器与算法、高级主题四个维度,提炼全书核心知识点。

后续会进行单一详细讲解。

目录

第一章 开始

第二章 变量和基本类型

第三章 字符串 向量 数组

第四章 表达式

第五章 语句

第六章 函数

第七章 类

第八章 IO库

第九章 顺序容器

第10章 泛型算法

第11章 关联容器

第12章 动态内存

第13章 拷贝控制

第14章 重载运算与类型转换

第15章 面向对象程序设计

    概述、虚函数、抽象基类、访问控制与继承、继承中类的作用、构造函数与拷贝控制、容器与继承、文本查询程序再探

第16章 模板与泛型编程

    定义模板、模板实参推断、重载与模板、可变参数模板

第17章 标准库特殊设施

    tuple类型、bitset类型、正则表达式、随机数、IO库再探。

第18章 用于大型程序的工具

    异常处理、命名空间、多重继承与虚继承。

第19章 特殊工具与技术

附录A 标准库

C++11新特性

简单总结主要内容:

一、基础概念与语法

这部分是 C++ 的 “基石”,涵盖程序结构、数据类型、表达式与语句等核心语法,是后续学习的基础。

1. 程序结构与基本语法

  • 程序入口

    所有 C++ 程序的入口都是main()函数,其返回类型必须是int(返回 0 表示程序正常结束,非 0 表示错误状态)。

  • 头文件与命名空间

    • 标准库头文件不带.h后缀(如<iostream>而非<iostream.h>),非标准库头文件可能带后缀。

    • std

      是 C++ 标准库的命名空间,使用标准库组件需显式声明:using namespace std;(全局使用)或std::cout(局部限定),避免命名冲突。

  • 输入输出

    • 标准输入流cin(搭配>>)、标准输出流cout(搭配<<)、标准错误流cerr(用于输出错误信息,不缓冲),定义在<iostream>中。

2. 数据类型与变量

C++ 数据类型分为基本类型复合类型,核心是理解 “类型的意义(内存占用、取值范围)” 与 “变量的生命周期”。

(1)基本类型

类型类别

具体类型

核心说明

布尔型

bool

取值仅true(1)或false(0),占用 1 字节。

字符型

char

/wchar_t/char16_t

char

占 1 字节(区分signed char/unsigned char),后两者用于宽字符。

整数型

short

/int/long/long long

大小关系:shortintlonglong longint通常 4 字节,long long8 字节。

浮点型

float

/double/long double

float

(4 字节,精度 6-7 位)、double(8 字节,精度 15-17 位),优先用double

(2)复合类型
  • 引用(&)

    变量的 “别名”,必须初始化且绑定后不可更改,常用于函数参数(避免拷贝)和返回值(返回对象而非拷贝)。示例:int a = 10; int &ref = a; ref = 20; // a的值变为20

  • 指针(*)

    存储变量地址的变量,可空(nullptr,C++11 新增,替代NULL)、可指向不同对象,需注意 “空指针”“野指针”(未初始化 / 指向已释放内存)的风险。示例:int a = 10; int *p = &a; *p = 20; // a的值变为20

  • const 限定符

    修饰变量为 “只读”,需初始化;修饰指针时需区分 “指针本身不可变”(int *const p)和 “指向的内容不可变”(const int *p)。核心原则:const修饰 “其右侧最近的变量或指针”。

3. 表达式与语句

  • 运算符优先级

    算术运算符(*//优先于+/-)> 关系运算符(>/<)> 逻辑运算符(&&优先于||)> 赋值运算符(=),不确定时用括号。

  • 递增 / 递减运算符

    ++i(前置,先自增再使用)比i++(后置,先使用再自增)更高效(避免临时变量),尤其在循环或容器迭代中优先使用前置。

  • 条件语句与循环

    • 条件语句:if-else(支持初始化语句,如if (int a = 10; a > 5))、switch(case 需加break,否则 “穿透”,支持string和枚举类型)。

    • 循环语句:for(C++11 支持 “范围 for”,for (auto x : container))、whiledo-while(至少执行一次)。

二、C++11 核心特性(重点)

1. 自动类型推断(auto)

作用:让编译器根据初始化值自动推导变量类型,简化代码(尤其面对复杂类型如迭代器、容器元素类型时)。

规则:

    • 必须初始化(否则无法推导类型)。

    • 推导引用时需显式加&(如auto &x = a,推导为引用类型)。

    • 推导const时,若变量是拷贝初始化(如auto x = const_a),const会丢失;若为引用初始化(auto &x = const_a),const会保留。

示例:

vector<int> vec = {1,2,3}; auto it = vec.begin(); // it类型为vector<int>::iterator。

2. 列表初始化({})

  • 作用:统一初始化语法,支持所有类型(基本类型、数组、容器、类对象),且能避免 “窄化转换”(如int a = {3.14}会编译报错,而int a = 3.14仅警告)。

  • 场景:

    • 变量初始化:int a{10}; double b{3.14};

    • 容器初始化:vector<int> vec{1,2,3}; map<string, int> mp{{"a",1}, {"b",2}};

    • 类对象初始化:class A { int x; }; A a{5};(需类支持聚合初始化或有匹配构造函数)。

3. 范围 for 循环

  • 语法:for (declaration : sequence),遍历序列(数组、容器、初始化列表等)的每个元素,无需手动管理索引或迭代器。

  • 注意:

    • 若需修改元素,declaration需为引用(auto &x);若只读,可用const auto &x(避免拷贝,高效)。

    • 序列必须是可遍历的(即有begin()end()成员,或能被标准库begin()/end()函数处理)。

  • 示例:vector<int> vec{1,2,3}; for (auto &x : vec) x *= 2; // vec变为{2,4,6}

4. 智能指针(RAII 机制)

C++11 引入智能指针,解决 “手动管理动态内存导致的内存泄漏、野指针” 问题,核心是RAII(资源获取即初始化):将资源(如动态内存)与对象生命周期绑定,对象销毁时自动释放资源。

三大智能指针定义在<memory>头文件中,对比如下:

智能指针类型

核心功能

使用场景

注意事项

unique_ptr

独占所有权,同一时间仅一个unique_ptr指向对象,不可拷贝(可移动)。

管理单个动态对象,无需共享所有权。

不可用operator=拷贝,需用std::move()转移所有权;数组需显式指定unique_ptr<T[]>

shared_ptr

共享所有权,多个shared_ptr指向同一对象,内部维护 “引用计数”,计数为 0 时释放对象。

需共享对象所有权(如容器存储指针、多线程共享对象)。

避免 “循环引用”(如两个shared_ptr互相指向对方,导致计数无法归零,内存泄漏),需配合weak_ptr解决。

weak_ptr

弱引用,指向shared_ptr管理的对象,但不增加引用计数,可检测对象是否存活。

解决shared_ptr的循环引用问题。

不能直接访问对象,需通过lock()获取shared_ptr(若对象存活则返回有效shared_ptr,否则返回空)。

示例(unique_ptr):

unique_ptr<int> up(new int(10)); // 独占管理动态intunique_ptr<int> up2 = move(up); // 转移所有权,up变为空// 无需手动delete,up2销毁时自动释放内存

5. 右值引用与移动语义(&&)

C++11 引入 “右值引用”,解决 “拷贝大量数据导致的性能浪费” 问题,核心是区分 “左值”(可取地址、有名字的对象,如变量a)和 “右值”(不可取地址、临时存在的对象,如字面量10、函数返回的临时对象)。

  • 右值引用(&&)

    只能绑定右值,用于 “窃取” 右值的资源(而非拷贝),实现 “移动语义”。

  • 移动构造函数 / 移动赋值运算符

    • 当用右值初始化对象时,编译器优先调用移动构造函数(而非拷贝构造),直接 “接管” 右值的内存,避免拷贝。

    • 若类未定义移动操作,编译器会用拷贝操作替代。

  • 示例(移动语义):

vector<int> func() { return vector<int>{1,2,3}; } // 返回临时对象(右值)
vector<int> vec1 = func(); // 调用移动构造,窃取临时对象的内存,无拷贝
vector<int> vec2 = move(vec1); // 强制将vec1(左值)转为右值,调用移动构造,vec1变为空

三、容器与算法(STL 核心)

C++ 标准库(STL)的 “容器 - 迭代器 - 算法” 模型是 C++ 的精髓,《C++ Primer》用大量篇幅讲解其使用与原理。

1. 容器分类与特性

STL 容器分为序列容器(按顺序存储,元素有位置关系)和关联容器(按键存储,支持快速查找),还有容器适配器(基于其他容器封装,接口更简单)。

(1)序列容器(定义在<vector>/<list>/<deque>等头文件)

容器类型

底层实现

核心优势

核心劣势

适用场景

vector

动态数组

随机访问([]at())高效(O (1)),尾插 / 尾删高效(O (1))。

中间插入 / 删除低效(O (n),需移动元素),扩容时可能拷贝数据。

需频繁随机访问、尾插,且插入 / 删除少的场景(如存储列表数据、缓冲区)。

list

双向链表

任意位置插入 / 删除高效(O (1)),内存不连续,无需扩容。

不支持随机访问(只能迭代遍历,O (n)),每个元素需额外存储指针,内存开销大。

需频繁插入 / 删除,且无需随机访问的场景(如实现链表、队列)。

deque

分段动态数组

两端插入 / 删除高效(O (1)),支持随机访问(O (1))。

中间插入 / 删除低效(O (n)),随机访问效率略低于vector

需两端操作、随机访问的场景(如实现栈、队列的底层容器)。

array

固定大小数组

栈上存储,内存高效,随机访问 O (1),大小编译期确定。

大小不可变,不能动态扩容。

存储固定大小的数据(如存储 3 个坐标值array<int,3>)。

(2)关联容器(定义在<map>/<set>等头文件)

关联容器分为有序(基于红黑树实现,自动按键排序,查找 O (log n))和无序(基于哈希表实现,查找 O (1) 平均情况)。

容器类型

键 - 值关系

有序 / 无序

核心特性

set

仅存储键(键唯一)

有序

自动按键升序排序,键不可重复,查找是否存在某键高效。

multiset

仅存储键(键可重复)

有序

set类似,但键可重复,适合存储可重复的有序数据(如统计成绩出现次数)。

map

键 - 值对(键唯一)

有序

自动按键升序排序,键不可重复,通过键快速查找值(map[key]find())。

multimap

键 - 值对(键可重复)

有序

map类似,但键可重复,适合存储一对多的映射(如一个键对应多个值)。

unordered_set

仅存储键(键唯一)

无序

哈希表实现,查找速度更快(平均 O (1)),键无序,不支持按键排序。

unordered_map

键 - 值对(键唯一)

无序

哈希表实现,适合高频查找场景(如缓存、字典),键无序。

(3)容器适配器
  • stack

    栈(LIFO,后进先出),默认基于deque实现,支持push()(压栈)、pop()(出栈)、top()(取栈顶)。

  • queue

    队列(FIFO,先进先出),默认基于deque实现,支持push()(入队)、pop()(出队)、front()(取队首)。

  • priority_queue

    优先队列(默认大顶堆),默认基于vector实现,支持push()(插入)、pop()(删除堆顶)、top()(取堆顶)。

2. 迭代器

迭代器是 “连接容器与算法的桥梁”,行为类似指针,用于遍历容器元素,不同容器的迭代器功能不同,分为 5 类(从弱到强):

  • 输入迭代器

    仅支持读、++(单向),如istream_iterator

  • 输出迭代器

    仅支持写、++(单向),如ostream_iterator

  • 前向迭代器

    支持读、写、++(单向),如forward_list的迭代器。

  • 双向迭代器

    支持读、写、++/--(双向),如listmap的迭代器。

  • 随机访问迭代器

    支持读、写、++/--、随机访问(+n/-n/[]),如vectordequearray的迭代器。

核心操作

  • *it

    访问迭代器指向的元素。

  • it->

    访问迭代器指向对象的成员(如map的迭代器指向pairit->first获取键)。

  • ++it

    迭代器向后移动(优先使用前置)。

  • it1 == it2

    判断两个迭代器是否指向同一位置。

注意:容器的erase()操作会使 “指向被删除元素的迭代器失效”,需通过erase()的返回值(指向被删除元素的下一个元素)更新迭代器,避免野指针。

3. 算法(STL 算法库)

STL 算法定义在<algorithm>头文件中,分为非修改算法(不改变容器元素,如查找、计数)和修改算法(改变容器元素,如排序、拷贝、替换),均通过迭代器操作容器,与容器类型无关。

常用算法示例:

  • 查找

    find(beg, end, val)(在[beg,end)中查找val,返回迭代器,未找到返回end)、count(beg, end, val)(计数val出现次数)。

  • 排序

    sort(beg, end)(默认升序排序,需随机访问迭代器,如vector)、stable_sort(beg, end)(稳定排序,保持相等元素的相对位置)。

  • 拷贝

    copy(beg_in, end_in, beg_out)(将[beg_in,end_in)的元素拷贝到beg_out开始的位置,需确保目标空间足够)。

  • 替换

    replace(beg, end, old_val, new_val)(将[beg,end)中所有old_val替换为new_val)。

  • 累加

    accumulate(beg, end, init)(从init开始,累加[beg,end)的元素,定义在<numeric>头文件)。

四、高级主题

1. 函数与函数模板

  • 函数参数

    支持默认参数(默认参数需从右往左定义,如void func(int a, int b=10))、可变参数(C++11 的initializer_list<T>,用于接收任意数量的同类型参数,如void func(initializer_list<int> args))。

  • 函数重载

    同一作用域内,函数名相同但参数列表(参数个数、类型、顺序)不同,编译器根据实参匹配最佳函数;返回值类型不同不能构成重载。

  • 函数模板

    定义通用函数,编译器根据实参类型自动生成具体版本(模板实例化),语法:template <typename T> T add(T a, T b) { return a + b; },支持模板特化(为特定类型定制实现)。

2. 类与对象

  • 类的基本成员

    成员变量(可加public/private/protected访问控制,默认private)、成员函数(普通成员函数、构造函数、析构函数、静态成员函数)。

  • 构造函数

    用于初始化对象,无返回值,与类名相同;支持重载、默认构造函数(无参数或参数全有默认值,若用户定义了其他构造函数,编译器不再生成默认构造)、拷贝构造函数(用同类型对象初始化新对象,默认浅拷贝,若有动态内存需自定义深拷贝)。

  • 析构函数

    用于释放对象资源(如动态内存、文件句柄),无参数、无返回值,与类名相同且加~,仅一个;若类有动态内存,必须自定义析构函数,避免内存泄漏。

  • 静态成员

    static修饰,属于类而非对象,所有对象共享;静态成员变量需在类外初始化,静态成员函数无this指针,不能访问非静态成员。

3. 继承与多态

  • 继承

    子类(派生类)继承父类(基类)的成员,语法:class Derived : public Base { ... };访问控制:public继承(基类public成员为子类publicprotectedprotected)、private继承(基类成员均为子类private)、protected继承(基类public/protected成员为子类protected)。

  • 多态

    通过 “虚函数” 实现,基类声明虚函数(virtual void func()),子类重写(override,C++11 关键字,显式声明重写,避免错误),通过基类指针 / 引用调用时,会根据对象实际类型调用对应版本的函数。

  • 抽象类

    包含纯虚函数(virtual void func() = 0)的类,不能实例化,只能作为基类,子类必须重写纯虚函数才能实例化。

4. 异常处理

  • 语法:try(包裹可能抛出异常的代码)、throw(抛出异常,可抛任意类型)、catch(捕获异常,按类型匹配,...捕获所有类型异常)。

  • 原则:异常用于处理 “异常情况”(如文件打开失败、内存分配失败),而非正常逻辑判断;抛出的异常应能被捕获,否则程序终止;C++ 标准库定义了标准异常类(如std::runtime_errorstd::out_of_range),可自定义异常类继承自标准异常。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐