C++进阶(上)

C++基础内容主要包括:

C++的数据类型、常量与变量、运算符、命名空间、输入输出、程序运行结构、数组、指针、

内存模型、函数、结构体、引用、类(封装继承多态)、友元和模版。

C++的基础内容相当于是入门知识,配合简单的题目,认真学习4到5天即可学习完成,相当于达到了能手敲图书管理系统的水平。

复习知识CSDN有很多文章,推荐链接,1小时即可看完。

C++进阶学习路线总览

首先需要了解代码编写规范

接着学习C++的STL(Standard Template Library,标准模板库),可配合数据结构的相关知识

  • 线性结构:数组、链表、栈、队列;
  • 树形结构:二叉树、红黑树;
  • 哈希结构:哈希表、哈希冲突解决(链地址法);
  • 算法基础:排序(快速排序、归并排序)、查找(二分查找)。

然后学习现代C++核心特性,重点包括智能指针(RAII思想 )、右值引用与移动语义、Lambda表达式和自动类型推导等C++11/14新特性;

然后学习C++的异常安全与错误处理

然后学习C++的代码调试方法(GDB)和性能分析(perf/valgrind);

最后学习扩展知识,如设计模式、并发编程、网络编程等。

代码编写规范

1.1 常量命名

// 规范:全大写,下划线分隔,放在常量区或使用 constexpr

const int MAX_BUFFER_SIZE = 1024; // 全局常量

const double PI = 3.14159265358979323846; // 数学常数

constexpr int DEFAULT_TIMEOUT_MS = 5000; // 编译期常量(C++11)

1.2 变量命名

// 规范:小写字母,下划线分隔(snake_case),见名知意

int user_count = 0;

std::string file_path;

1.3 函数命名

// 规范:小写字母,下划线分隔,动词开头

int calculate_sum(int a, int b); // ✅ 动词开头

bool is_valid_user(const std::string& name); // ✅ 布尔值用 is/has/can

std::string get_user_name(); // ✅ 获取值用 get

void set_user_name(const std::string& name); // ✅ 设置值用 set

1.4 类命名

// 规范:大驼峰(PascalCase),名词

class UserProfile; // ✅ 好

class UserManager; // ✅ 好

1.5 成员变量命名

// 规范:小写+下划线,可选后缀下划线表示成员

class GoodExample {

public:

// 公共成员使用正常命名

int public_value;

private:

// 私有成员可选下划线后缀,便于区分

int private_value_; // ✅ 常见风格

std::string user_name_; // ✅ 带下划线后缀

};

2.1 文件头注释

/**

* @file user_manager.h

* @brief 用户管理器类,负责用户的增删改查操作

* @author Your Name

* @date 2024-01-01

*/

2.2 类注释

/**

* @class UserManager

* @brief 管理用户数据的类,提供CRUD操作

*

* @details 这个类负责:

* - 添加新用户到数据库

* - 根据ID查询用户

* - 更新用户信息

* - 删除用户

*/

2.3 函数注释

/**

* @brief 根据用户ID获取用户名

*

* @param user_id 用户ID,必须大于0

* @return std::string 用户名,如果未找到返回空字符串

*

* @throws std::invalid_argument 如果 user_id <= 0

*

* @example

* @code

* UserManager mgr;

* std::string name = mgr.get_user_name(100);

* @endcode

*/

std::string get_user_name(int user_id);

3.1 避免野指针

// 正确做法1:使用智能指针

void demo_smart_pointer() {

// unique_ptr:独占所有权,自动释放

std::unique_ptr<int> smart_ptr = std::make_unique<int>(42);

// 使用指针

std::cout << "Value: " << *smart_ptr << std::endl;

// 函数结束自动释放,无需手动 delete

}

// 正确做法2:使用前检查

void demo_safe_pointer() {

int* ptr = new int(10);

// 使用前检查

if (ptr != nullptr) {

*ptr = 20; // 安全

}

delete ptr; // 记得释放

ptr = nullptr; // 释放后置空,防止悬空指针

}

3.2 避免内存泄漏

3.3 避免数组越界

3.4 避免未初始化变量

3.5 使用 const 保护数据

3.6 使用 enum class 代替 enum

快速参考:命名规范总结

类型 规范 示例


类/结构体 大驼峰 UserManager, BankAccount

函数 小写+下划线 get_user_name(), calculate_sum()

变量 小写+下划线 user_count, file_path

常量 全大写+下划线 MAX_BUFFER_SIZE, PI

成员变量 小写+下划线+_ user_name_, balance_

私有成员 可选下划线后缀 private_value_

命名空间 小写+下划线 my_project::database

枚举值 小写+前缀k Color::kRed, Status::kOk

模板参数 大驼峰或尾缀T TemplateType, T

C++STL

STL 是 C++ 官方提供的通用数据结构和算法库,核心是容器、算法、迭代器,能直接用于工程开发;学习 STL 是提升 C++ 开发效率、对接项目需求的核心步骤,也是面试必考内容。

步骤1:STL容器

序列容器

  • `std::vector` - 动态数组(最常用)

  • `std::deque` - 双端队列

  • `std::list` - 双向链表

  • `std::array` - 固定大小数组(C++11)

关联容器

  • `std::pair` - 键值对

  • `std::map` - 键值对映射(有序)

  • `std::unordered_map` - 哈希表映射(无序,更快)

  • `std::set` - 集合(有序,唯一)

  • `std::unordered_set` - 哈希集合(无序,唯一)

字符串

  • `std::string` - 字符串类

  • 字符串操作:查找、替换、子串

  • 字符串与数字互转

01:std::vector(重点)

/*

* vector 是什么?

* - 动态数组,大小可以自动增长

* - 元素在内存中连续存储(和数组一样)

* - 支持随机访问,通过下标快速访问任何元素

*

* 什么时候使用 vector?

* - 需要动态大小的数组

* - 需要频繁随机访问元素

* - 不需要在中间频繁插入/删除

*

* vector vs 数组:

* 数组 vector

* --------------------------------------------

* 大小固定 是 否

* 自动管理内存 否 是

* 知道自己大小 否 是 (size())

* 边界检查 否 有 at()

*/

创建vector

// 1. 空vector

vector<int> v1; // 创建空的int vector

cout << "v1 大小: " << v1.size() << endl; // 输出: 0

// 2. 指定大小和初始值

vector<int> v2(5); // 5个元素,默认值为0

cout << "v2: ";

for (int x : v2) cout << x << " "; // 输出: 0 0 0 0 0

cout << endl;

vector<int> v3(5, 10); // 5个元素,每个都是10

cout << "v3: ";

for (int x : v3) cout << x << " "; // 输出: 10 10 10 10 10

cout << endl;

// 3. 用初始化列表

vector<int> v4 = {1, 2, 3, 4, 5};

vector<int> v5{1, 2, 3, 4, 5}; // 等价写法(C++11)

// 4. 用另一个vector初始化

vector<int> v6(v4); // 拷贝v4

vector<int> v7 = v4; // 也是拷贝

// 5. string的vector

vector<string> words = {"hello", "world", "cpp"};

遍历 vector

vector<int> v = {1, 2, 3, 4, 5};

// 方法1: 传统for循环(需要索引时用)

cout << "传统for: ";

for (size_t i = 0; i < v.size(); ++i) {

cout << v[i] << " ";

}

cout << endl;

// 方法2: 范围for循环(C++11,最常用,最安全)

cout << "范围for: ";

for (int x : v) {

cout << x << " ";

}

cout << endl;

// 方法3: 范围for + 引用(需要修改元素时用)

cout << "修改后: ";

for (int& x : v) { // 注意:是 int& 不是 int

x *= 2; // 每个元素乘以2

}

// 方法4: 迭代器

cout << "迭代器: ";

for (auto it = v.begin(); it != v.end(); ++it) {

cout << *it << " ";

}

vector 常用操作速查表

操作 说明


v.size() 元素个数

v.empty() 是否为空

v.capacity() 容量

v.reserve(n) 预分配容量

v.resize(n) 调整大小

v.clear() 清空

v.push_back(x) 末尾添加

v.pop_back() 删除末尾

v[i] 访问(不检查边界)

v.at(i) 访问(检查边界)

v.front() 访问第一个元素

v.back() 访问最后一个元素

v.insert(pos, x) 插入

v.erase(pos) 删除

v.data() 获取原始指针

02:list - 双向链表(重点)

* list 是什么?

* - 双向链表容器

* - 元素在内存中不连续存储

* - 每个元素包含指向前一个和后一个元素的指针

*

* 什么时候使用 list?

* - 需要频繁在中间插入/删除元素

* - 不需要随机访问

* - 迭代器不会失效(除了被删除的那个)

list基础

// 1. 创建和初始化

list<int> lst1; // 空 list

list<int> lst2(5, 10); // 5个10

list<int> lst3 = {1, 2, 3, 4, 5}; // 初始化列表

// 2. 添加元素

lst1.push_back(10); // 末尾添加

lst1.push_front(5); // 开头添加

cout << "lst1: ";

for (int x : lst1) cout << x << " "; // 5 10

cout << endl;

// 3. 访问元素

cout << "front: " << lst1.front() << endl; // 5

cout << "back: " << lst1.back() << endl; // 10

// 注意:list 不支持 [] 和 at()(没有随机访问)

// 4. 大小相关

cout << "size: " << lst1.size() << endl;

cout << "empty: " << (lst1.empty() ? "yes" : "no") << endl;

// 5. 删除元素

lst1.pop_front(); // 删除开头

lst1.pop_back(); // 删除末尾

list插入和删除操作

list<int> lst = {10, 20, 30, 40, 50};

// 1. 在指定位置插入(需要迭代器)

auto it = lst.begin();

advance(it, 2); // 移动到第3个元素

lst.insert(it, 25); // 在索引2处插入25

cout << "插入后: ";

for (int x : lst) cout << x << " "; // 10 20 25 30 40 50

cout << endl;

// 2. 插入多个元素

it = lst.begin();

advance(it, 1);

lst.insert(it, 3, 15); // 插入3个15

cout << "插入多个后: ";

for (int x : lst) cout << x << " ";

cout << endl;

// 3. 删除指定位置

it = lst.begin();

advance(it, 4); // 移动到第5个元素

lst.erase(it); // 删除该元素

cout << "删除后: ";

for (int x : lst) cout << x << " ";

cout << endl;

// 4. 删除范围内的元素

auto first = lst.begin();

auto last = lst.begin();

advance(first, 1);

advance(last, 4);

lst.erase(first, last); // 删除索引1-3的元素

cout << "删除范围后: ";

for (int x : lst) cout << x << " ";

cout << endl;

// 5. 删除特定值的所有元素

lst = {1, 2, 2, 3, 2, 4};

lst.remove(2); // 删除所有值为2的元素

cout << "remove(2)后: ";

for (int x : lst) cout << x << " "; // 1 3 4

cout << endl;

// 6. 删除满足条件的元素

lst = {1, 2, 3, 4, 5, 6};

lst.remove_if([](int x) { return x % 2 == 0; }); // 删除偶数

cout << "删除偶数后: ";

for (int x : lst) cout << x << " "; // 1 3 5

list 的特有操作

list<int> lst1 = {1, 2, 3};

list<int> lst2 = {4, 5, 6};

// 1. splice - 转移元素(不拷贝,只是移动指针)

cout << "splice 前 lst1: ";

for (int x : lst1) cout << x << " ";

cout << endl;

auto it = lst1.begin();

advance(it, 1);

lst1.splice(it, lst2); // 将lst2所有元素插入到lst1的it位置

cout << "splice 后 lst1: ";

for (int x : lst1) cout << x << " "; // 1 4 5 6 2 3

cout << endl;

cout << "splice 后 lst2 大小: " << lst2.size() << endl; // 0(被搬空了)

// 2. merge - 合并两个有序列表

list<int> lst3 = {1, 3, 5, 7};

list<int> lst4 = {2, 4, 6, 8};

lst3.merge(lst4); // lst3和lst4必须都已排序

cout << "\nmerge 后: ";

for (int x : lst3) cout << x << " "; // 1 2 3 4 5 6 7 8

cout << endl;

// 3. sort - 排序(list有自己的sort,比通用算法更高效)

list<int> lst5 = {5, 2, 8, 1, 9};

lst5.sort(); // 升序

cout << "\nsort(升序): ";

for (int x : lst5) cout << x << " ";

cout << endl;

lst5.sort(greater<int>()); // 降序

cout << "sort(降序): ";

for (int x : lst5) cout << x << " ";

cout << endl;

// 4. reverse - 反转

lst5.reverse();

cout << "reverse: ";

for (int x : lst5) cout << x << " ";

cout << endl;

// 5. unique - 删除连续重复元素

list<int> lst6 = {1, 1, 2, 2, 2, 3, 3};

lst6.unique();

cout << "\nunique: ";

for (int x : lst6) cout << x << " "; // 1 2 3

03:pair - 键值对基础

// 1. 创建 pair

pair<string, int> p1("Alice", 25);

cout << "p1: " << p1.first << ", " << p1.second << endl;

// 2. 使用 make_pair(类型推导)

auto p2 = make_pair("Bob", 30);

cout << "p2: " << p2.first << ", " << p2.second << endl;

// 3. 初始化列表(C++11)

pair<string, int> p3{"Charlie", 35};

04:map-有序键值对映射

// 1. 创建和初始化

map<string, int> scores;

scores = {

{"Alice", 90},

{"Bob", 85},

{"Charlie", 95}

};

// 2. 访问元素

cout << "Alice 的分数: " << scores["Alice"] << endl;

cout << "Bob 的分数: " << scores.at("Bob") << endl;

// 3. 添加/修改元素

scores["David"] = 88; // 添加

scores["Alice"] = 92; // 修改

05:unordered_map - 哈希表映射(重点)

unordered_map 使用哈希表,平均 O(1) 查找

// 1. 查找

auto it = ages.find("Bob");

if (it != ages.end()) {

cout << "找到: " << it->first << " -> " << it->second << endl;

}

// 2. 遍历(注意:无序!)

for (const auto& [name, age] : ages) {

cout << " " << name << ": " << age << endl;

}

// 3. 哈希表特性

cout << "\nunordered_map 特性:" << endl;

cout << " 桶数量: " << ages.bucket_count() << endl;

cout << " 最大桶数: " << ages.max_bucket_count() << endl;

cout << " 负载因子: " << ages.load_factor() << endl;

06:set - 有序集合

set 存储唯一值,自动排序(可去重)

set<int> s;

s.insert(5);

s.insert(2);

s.insert(8);

s.insert(2); // 重复值被忽略

for (int x : s) {

cout << x << " "; // 2 5 8

}

07:array

* array 是什么?

* - 固定大小数组的STL封装

* - 大小在编译时确定

* - 不分配动态内存,开销为零

*

* 什么时候使用 array?

* - 知道数组大小,不会改变

* - 需要STL接口(如begin/end, size)

* - 比原生数组更安全
// 1. 创建和初始化

array<int, 5> arr1; // 未初始化

array<int, 5> arr2{}; // 零初始化

array<int, 5> arr3{1, 2, 3, 4, 5}; // 列表初始化

array<int, 5> arr4 = {10, 20, 30}; // 剩余为0

// 2. 访问元素

cout << "arr3[0] = " << arr3[0] << endl;

cout << "arr3.at(1) = " << arr3.at(1) << endl;

cout << "front: " << arr3.front() << endl;

cout << "back: " << arr3.back() << endl;

// 3. 大小

cout << "size: " << arr3.size() << endl; // 编译期常量

// 4. 遍历

cout << "遍历: ";

for (int x : arr3) {

cout << x << " ";

}
array<int, 10> arr = {5, 2, 8, 1, 9, 3, 7, 4, 6, 0};

// 1. 排序

sort(arr.begin(), arr.end());

cout << "排序后: ";

for (int x : arr) cout << x << " ";

cout << endl;

// 2. 查找

auto it = find(arr.begin(), arr.end(), 5);

if (it != arr.end()) {

cout << "找到 5,位置: " << distance(arr.begin(), it) << endl;

}

// 3. 二分查找

bool found = binary_search(arr.begin(), arr.end(), 7);

cout << "7 存在: " << (found ? "是" : "否") << endl;

// 4. 统计

int count = std::count(arr.begin(), arr.end(), 5);

cout << "5 的个数: " << count << endl;

// 5. 遍历修改

for_each(arr.begin(), arr.end(), [](int& x) { x *= 2; });

cout << "翻倍后: ";

for (int x : arr) cout << x << " ";

cout << endl;

// 6. 填充

arr.fill(0);

cout << "fill(0)后: ";

for (int x : arr) cout << x << " ";

cout << endl;

08:string

// 1. 创建和初始化

string s1; // 空字符串

string s2 = "Hello"; // 从字符串字面量

string s3("World"); // 构造函数

string s4(5, 'A'); // 5个'A': "AAAAA"

string s5(s2); // 拷贝构造

string s6 = s2 + " " + s3; // 拼接: "Hello World"
// 1. 比较运算符

cout << "apple == banana: " << (s1 == s2 ? "true" : "false") << endl;

cout << "apple < banana: " << (s1 < s2 ? "true" : "false") << endl;

cout << "apple == apple: " << (s1 == s3 ? "true" : "false") << endl;

// 2. compare() 函数(类似strcmp)

int result = s1.compare(s2);

if (result < 0) {

cout << "apple < banana (compare返回负数)" << endl;

} else if (result > 0) {

cout << "apple > banana (compare返回正数)" << endl;

} else {

cout << "apple == banana (compare返回0)" << endl;

}

// 3. 部分比较

result = s1.compare(1, 3, s3); // 比较s1[1:3]和s3

cout << "\"ppl\" 与 \"apple\" 比较: " << result << endl;
// 1. to_string() - 数字转字符串

int i = 42;

double d = 3.14159;

string s_i = to_string(i);

string s_d = to_string(d);

cout << "int to string: " << s_i << endl;

cout << "double to string: " << s_d << endl;

// 2. stoi() - 字符串转整数

string num_str = "123";

int num = stoi(num_str);

cout << "string to int: " << num << endl;

// 3. stod() - 字符串转浮点数

string pi_str = "3.14159";

double pi = stod(pi_str);

cout << "string to double: " << pi << endl;

09迭代器

* 什么是迭代器?

* - 迭代器是STL连接容器和算法的"桥梁"

* - 提供统一的方式访问容器中的元素

* - 类似指针,但更安全、更通用

*

* 为什么需要迭代器?

* - 使算法与容器解耦

* - 同一个算法可以用于不同容器

* - 提供安全的访问方式
vector<int> v = {1, 2, 3, 4, 5};

// begin() / end() - 返回可修改的迭代器

cout << "使用 begin/end: ";

for (auto it = v.begin(); it != v.end(); ++it) {

*it *= 2; // 可以修改元素

cout << *it << " ";

}

cout << endl;

// cbegin() / cend() - 返回 const 迭代器(只读)

cout << "使用 cbegin/cend: ";

for (auto it = v.cbegin(); it != v.cend(); ++it) {

// *it *= 2; // ❌ 编译错误!不能修改

cout << *it << " ";

}

cout << endl;

// rbegin() / rend() - 反向迭代器

cout << "使用 rbegin/rend(反向): ";

for (auto it = v.rbegin(); it != v.rend(); ++it) {

cout << *it << " ";

}

cout << endl;

// crbegin() / crend() - const 反向迭代器

cout << "使用 crbegin/crend(const反向): ";

for (auto it = v.crbegin(); it != v.crend(); ++it) {

cout << *it << " ";

}
vector<int> v = {10, 20, 30, 40, 50};

// 1. 解引用:*it 获取元素

auto it = v.begin();

cout << "*it = " << *it << endl; // 输出: 10

// 2. 箭头操作:it-> 访问成员(元素是类对象时)

vector<string> words = {"hello", "world"};

auto word_it = words.begin();

cout << "word_it->size() = " << word_it->size() << endl; // 输出: 5

// 3. 前置/后置递增

++it; // 前置:返回递增后的值(更高效)

it++; // 后置:返回递增前的值

cout << "++it 后: " << *it << endl; // 输出: 20

// 4. 前置/后置递减(双向迭代器以上)

--it;

cout << "--it 后: " << *it << endl; // 输出: 10

// 5. 随机访问(仅随机访问迭代器)

it = v.begin();

it += 2; // 向前移动2步

cout << "it += 2: " << *it << endl; // 输出: 30

it = v.begin() + 3; // 直接跳到第4个元素

cout << "begin() + 3: " << *it << endl; // 输出: 40

// 6. 迭代器相减(仅随机访问迭代器)

auto first = v.begin();

auto last = v.end();

cout << "距离: " << (last - first) << endl; // 输出: 5

// 7. 比较迭代器

if (v.begin() != v.end()) {

cout << "容器不为空" << endl;

}

10:适配器和仿函数

适配器不是「全新的组件」,而是对容器、迭代器、仿函数进行「包装」,改变其原有接口,适配新的使用场景 。因此适配器分为容器适配器(stack(栈)、queue(队列)、priority_queue(优先队列))、迭代器适配器reverse_iterator(反向迭代器)和仿函数适配器。

适配器的核心是容器适配器

  • stack(栈):基于deque(默认)/vector/list包装,只暴露「尾部插入 / 删除 / 访问」接口(LIFO,后进先出);
  • queue(队列):基于deque(默认)包装,只暴露「尾部插入、头部删除、访问」接口(FIFO,先进先出);
  • priority_queue(优先队列):基于vector(默认)+ 堆算法实现,自动按优先级排序(默认大顶堆)。

仿函数 = 可以像函数一样调用的对象,本质是重载了 operator() 的类

它伪装成函数,但实际上是对象

// 定义仿函数:判断整数是否为偶数

struct IsEven {

// 重载()运算符,参数是要判断的整数,返回布尔值

bool operator()(int num) const {

// const保证仿函数不修改自身状态,符合STL算法要求

return num % 2 == 0; }

};

int main()

{ vector<int> nums = {1, 2, 3, 4, 5, 6, 7, 8};

// 使用仿函数:传入IsEven的临时对象作为判断规则

int even_count = count_if(nums.begin(), nums.end(), IsEven());

cout << "偶数的个数:" << even_count << endl; // 输出:4

return 0; }
template <class T>

struct greater {

bool operator()(const T& a, const T& b) const {

return a > b; }

};

11:STL总结--基于学生成绩管理系统

代码结构

StudentSystem/

├── student.h # 学生类定义

├── student.cpp # 学生类实现

├── grade_manager.h # 成绩管理器类定义

├── grade_manager.cpp # 成绩管理器类实现

├── main.cpp # 主程序入口

└── README.md

代码比较简单,直接编译即可:

g++ -std=c++17 main.cpp student.cpp grade_manager.cpp -o student_system

按照代码编写顺序来看

cpp 复制代码
//==============================================================
student.h - 学生类定义
//==============================================================

#ifndef STUDENT_H
#define STUDENT_H

#include <string>
#include <vector>

class Student {
public:
    // 构造函数
    Student();
    Student(int id, const std::string& name, int age);

    // 获取器
    int get_id() const;
    std::string get_name() const;
    int get_age() const;
    const std::vector<int>& get_grades() const;

    // 修改器
    void set_name(const std::string& name);
    void set_age(int age);

    // 成绩管理
    void add_grade(int grade);
    double get_average() const;
    int get_max_grade() const;
    int get_min_grade() const;
    size_t get_grade_count() const;

    // 显示信息
    void display() const;

    // 比较(用于排序)
    bool operator<(const Student& other) const;

private:
    int id_;
    std::string name_;
    int age_;
    std::vector<int> grades_;
};

#endif // STUDENT_H
cpp 复制代码
//==============================================================
student.cpp - 学生类实现
//==============================================================

#include "student.h"
#include <iostream>
#include <algorithm>
#include <numeric>
#include <iterator>

using namespace std;

// 构造函数
Student::Student() : id_(0), name_(""), age_(0) {}

Student::Student(int id, const string& name, int age)
    : id_(id), name_(name), age_(age) {}

// 获取器
int Student::get_id() const {
    return id_;
}

string Student::get_name() const {
    return name_;
}

int Student::get_age() const {
    return age_;
}

const vector<int>& Student::get_grades() const {
    return grades_;
}

// 修改器
void Student::set_name(const string& name) {
    name_ = name;
}

void Student::set_age(int age) {
    age_ = age;
}

// 成绩管理
void Student::add_grade(int grade) {
    grades_.push_back(grade);
}

double Student::get_average() const {
    if (grades_.empty()) {
        return 0.0;
    }

    // 使用 accumulate 算法求和
    int sum = accumulate(grades_.begin(), grades_.end(), 0);
    return static_cast<double>(sum) / grades_.size();
}

int Student::get_max_grade() const {
    if (grades_.empty()) {
        return 0;
    }

    // 使用 max_element 算法
    auto it = max_element(grades_.begin(), grades_.end());
    return *it;
}

int Student::get_min_grade() const {
    if (grades_.empty()) {
        return 0;
    }

    // 使用 min_element 算法
    auto it = min_element(grades_.begin(), grades_.end());
    return *it;
}

size_t Student::get_grade_count() const {
    return grades_.size();
}

// 显示信息
void Student::display() const {
    cout << "ID: " << id_
         << ", 姓名: " << name_
         << ", 年龄: " << age_
         << ", 平均分: " << get_average()
         << endl;
}

// 比较(用于排序)
bool Student::operator<(const Student& other) const {
    return id_ < other.id_;
}
cpp 复制代码
//==============================================================
 grade_manager.h - 成绩管理器类定义
//==============================================================

#ifndef GRADE_MANAGER_H
#define GRADE_MANAGER_H

#include "student.h"
#include <unordered_map>
#include <vector>
#include <functional>

class GradeManager {
public:
    // 构造函数
    GradeManager() = default;

    // ===== 学生管理 =====
    // 添加学生
    bool add_student(int id, const std::string& name, int age);

    // 删除学生
    bool remove_student(int id);

    // 查找学生
    Student* find_student(int id);
    const Student* find_student(int id) const;

    // 检查学生是否存在
    bool has_student(int id) const;

    // 获取所有学生
    std::vector<Student> get_all_students() const;

    // ===== 成绩管理 =====
    // 为学生添加成绩
    bool add_grade(int student_id, int grade);

    // ===== 统计功能 =====
    // 获取班级平均分
    double get_class_average() const;

    // 获取最高分学生
    std::vector<Student> get_top_students(int top_n = 1) const;

    // 按平均分排序的学生列表
    std::vector<Student> get_students_sorted_by_average() const;

    // 按条件筛选学生(使用仿函数/Lambda)
    std::vector<Student> filter_students(std::function<bool(const Student&)> predicate) const;

    // 统计各分数段人数
    struct GradeStats {
        int excellent;  // 90-100
        int good;       // 80-89
        int pass;       // 60-79
        int fail;       // 0-59
    };
    GradeStats get_grade_statistics() const;

    // ===== 显示功能 =====
    // 显示所有学生
    void display_all() const;

    // 显示统计信息
    void display_statistics() const;

    // 获取学生数量
    size_t get_student_count() const;

private:
    // 使用 unordered_map 存储学生(ID -> Student)
    std::unordered_map<int, Student> students_;
};

#endif // GRADE_MANAGER_H
cpp 复制代码
//==============================================================
grade_manager.cpp - 成绩管理器类实现
//==============================================================

#include "grade_manager.h"
#include <iostream>
#include <algorithm>
#include <numeric>
#include <sstream>

using namespace std;

// ===== 学生管理 =====

bool GradeManager::add_student(int id, const string& name, int age) {
    // 检查ID是否已存在
    if (students_.count(id) > 0) {
        cout << "错误: 学生ID " << id << " 已存在" << endl;
        return false;
    }

    // 使用 emplace 插入(更高效)
    students_.emplace(id, Student(id, name, age));
    cout << "添加学生: " << name << " (ID: " << id << ")" << endl;
    return true;
}

bool GradeManager::remove_student(int id) {
    // 使用 erase 删除
    size_t erased = students_.erase(id);
    if (erased > 0) {
        cout << "删除学生ID: " << id << endl;
        return true;
    }
    cout << "错误: 学生ID " << id << " 不存在" << endl;
    return false;
}

Student* GradeManager::find_student(int id) {
    auto it = students_.find(id);
    if (it != students_.end()) {
        return &(it->second);
    }
    return nullptr;
}

const Student* GradeManager::find_student(int id) const {
    auto it = students_.find(id);
    if (it != students_.end()) {
        return &(it->second);
    }
    return nullptr;
}

bool GradeManager::has_student(int id) const {
    return students_.count(id) > 0;
}

vector<Student> GradeManager::get_all_students() const {
    vector<Student> result;
    result.reserve(students_.size());

    // 使用 transform 算法提取学生
    transform(students_.begin(), students_.end(),
             back_inserter(result),
             [](const auto& pair) {
                 return pair.second;
             });

    return result;
}

// ===== 成绩管理 =====

bool GradeManager::add_grade(int student_id, int grade) {
    Student* student = find_student(student_id);
    if (student == nullptr) {
        cout << "错误: 学生ID " << student_id << " 不存在" << endl;
        return false;
    }

    student->add_grade(grade);
    cout << "为学生ID " << student_id << " 添加成绩: " << grade << endl;
    return true;
}

// ===== 统计功能 =====

double GradeManager::get_class_average() const {
    if (students_.empty()) {
        return 0.0;
    }

    double total = 0.0;
    int count = 0;

    // 使用范围for遍历
    for (const auto& [id, student] : students_) {
        double avg = student.get_average();
        if (avg > 0) {
            total += avg;
            count++;
        }
    }

    return count > 0 ? total / count : 0.0;
}

vector<Student> GradeManager::get_top_students(int top_n) const {
    auto all_students = get_students_sorted_by_average();

    // 截取前 top_n 个
    if (static_cast<size_t>(top_n) >= all_students.size()) {
        return all_students;
    }

    return vector<Student>(all_students.begin(),
                           all_students.begin() + top_n);
}

vector<Student> GradeManager::get_students_sorted_by_average() const {
    auto all = get_all_students();

    // 使用 sort 算法 + Lambda 排序
    sort(all.begin(), all.end(),
         [](const Student& a, const Student& b) {
             return a.get_average() > b.get_average();  // 降序
         });

    return all;
}

vector<Student> GradeManager::filter_students(function<bool(const Student&)> predicate) const {
    vector<Student> result;
    auto all = get_all_students();

    // 使用 copy_if 算法筛选
    copy_if(all.begin(), all.end(),
           back_inserter(result),
           predicate);

    return result;
}

GradeManager::GradeStats GradeManager::get_grade_statistics() const {
    GradeStats stats = {0, 0, 0, 0};

    // 遍历所有学生的所有成绩
    for (const auto& [id, student] : students_) {
        for (int grade : student.get_grades()) {
            if (grade >= 90) {
                stats.excellent++;
            } else if (grade >= 80) {
                stats.good++;
            } else if (grade >= 60) {
                stats.pass++;
            } else {
                stats.fail++;
            }
        }
    }

    return stats;
}

// ===== 显示功能 =====

void GradeManager::display_all() const {
    cout << "\n========== 所有学生 ==========" << endl;

    auto all = get_all_students();

    // 使用 for_each 算法显示
    for_each(all.begin(), all.end(),
             [](const Student& s) {
                 s.display();
             });

    cout << "总人数: " << all.size() << endl;
}

void GradeManager::display_statistics() const {
    cout << "\n========== 统计信息 ==========" << endl;

    cout << "学生总数: " << get_student_count() << endl;
    cout << "班级平均分: " << get_class_average() << endl;

    GradeStats stats = get_grade_statistics();
    cout << "成绩分布:" << endl;
    cout << "  优秀(90-100): " << stats.excellent << endl;
    cout << "  良好(80-89):  " << stats.good << endl;
    cout << "  及格(60-79):  " << stats.pass << endl;
    cout << "  不及格(0-59): " << stats.fail << endl;

    // 显示前3名
    auto top = get_top_students(3);
    cout << "\n成绩前三名:" << endl;
    for (size_t i = 0; i < top.size(); ++i) {
        cout << "  第" << (i + 1) << "名: "
             << top[i].get_name()
             << " (平均分: " << top[i].get_average() << ")" << endl;
    }
}

size_t GradeManager::get_student_count() const {
    return students_.size();
}

现代C++核心特性

现代 C++ 特性解决传统 C++ 的内存安全问题, 提升代码运行效率, 降低代码冗余度

A智能指针

* 智能指针是RAII(资源获取即初始化)的核心应用,

* 自动管理动态内存的生命周期,防止内存泄漏。

#include <memory> // 智能指针头文件

#include <utility>

unique_ptr - 独占所有权

// 创建方式1: make_unique (C++14推荐)

unique_ptr<Widget> w1 = make_unique<Widget>(1, "Unique Widget 1");

w1->greet();

// 创建方式2: new (不推荐,但需要知道)

unique_ptr<Widget> w2(new Widget(2, "Unique Widget 2"));

cout << "移动所有权:\n";

unique_ptr<Widget> w3 = move(w1); // w1变为空

// reset() 释放所有权

cout << "\nreset释放:\n";

w3.reset(); // 显式释放,Widget被析构

// release() 释放所有权但不删除对象

auto raw = w2.release(); // w2变为空,返回裸指针

cout << "w2是否为空: " << (w2 ? "否" : "是") << "\n";

delete raw; // 手动删除

shared_ptr - 共享所有权

// 创建方式1: make_shared (推荐,效率更高)

shared_ptr<Widget> s1 = make_shared<Widget>(100, "Shared Widget 1");

cout << "引用计数: " << s1.use_count() << "\n";

{

// 复制增加引用计数

shared_ptr<Widget> s2 = s1;

cout << "复制后引用计数: " << s1.use_count() << "\n";

s2->greet();

} // s2离开作用域,引用计数减1

cout << "s2离开作用域后引用计数: " << s1.use_count() << "\n";

// 移动不增加引用计数,转移所有权

shared_ptr<Widget> s3 = move(s1);

cout << "移动后s1引用计数: " << s1.use_count() << "\n";

cout << "移动后s3引用计数: " << s3.use_count() << "\n";

weak_ptr - 解决循环引用

node1->next = node2;

node2->next = node1; // weak_ptr不增加引用计数

B右值引用与移动语义

* 移动语义是C++11最重要的特性之一,通过"移动"而非"复制"

* 来避免不必要的资源拷贝,大幅提升性能。

int a = 10; // a是左值(有名字,有内存地址)

int& b = a; // b是左值引用

// int&& c = a; // 错误!不能将左值绑定到右值引用

int&& d = 10; // 10是右值(临时对象,无名字),d是右值引用

int&& e = a * 2; // a*2是右值表达式

cout << "\n判断方法:\n";

cout << "能取地址(&)的是左值,不能取地址的是右值\n";
void take_lvalue_ref(int& x) {

cout << " 接受左值引用: " << x << "\n";

}

void take_rvalue_ref(int&& x) {

cout << " 接受右值引用: " << x << "\n";

}

string str1 = "Hello";

cout << " str1: " << str1 << "\n";

// std::move将左值强制转换为右值引用

string str3 = move(str1); // str1的资源被"移动"到str3

std::move 的本质是「强制类型转换工具」,不是「移动数据的函数」:

  • std::move(x) 只做一件事:把「左值 x」强制转换成「右值引用类型」,让编译器选择调用「移动构造 / 赋值函数」,而非「拷贝构造 / 赋值函数」;
  • 真正执行「数据 / 资源转移」的是移动构造函数string 类实现的),不是 std::move
  • str1 变空,是 string 的移动构造函数「拿走了 str1 的资源」,和 std::move 本身无关。

string str3 = move(str1);

分两步执行,核心在第二步:

第一步:move(str1) ------ 仅做类型转换:把 str1 的类型从 std::string 转换成 std::string&&(右值引用);

第二步:string str3 = 右值引用 ------ 移动构造函数执行 "资源转移"

// string的移动构造函数(接收右值引用)

string(string&& other) noexcept { // 1. 拿走other的资源(指针指向"Hello"的内存)

this->data_ = other.data_;

this->size_ = other.size_;

// 2. 把other的资源置空(避免析构时重复释放)

other.data_ = nullptr;

other.size_ = 0;

}

std::forward 与完美转发

// 万能引用模板函数

template<typename T>

void relay(T&& arg) { // T&& 是万能引用,不是右值引用

cout << " relay收到: ";

if (std::is_lvalue_reference<T>::value) {

cout << "左值\n";

} else {

cout << "右值\n";

}

// 使用forward保持值类别

process(std::forward<T>(arg));

}

// 完美转发示例

template<typename T>

void wrapper(T&& arg) {

cout << " wrapper -> ";

// forward保持参数的左值/右值性质

process(std::forward<T>(arg));

}

CLambda表达式

* Lambda是C++11最重要的特性之一,提供匿名函数的便捷写法。

Lambda完整语法:

[捕获列表](参数列表) mutable(可选) exception(可选) -> 返回类型 { 函数体 };

Lambda 表达式的本质是 C++ 编译器自动生成的「匿名仿函数类(Functor)」的实例对象 ------ 它不是 "函数",而是一个「行为像函数的对象(可调用对象)」

// 1. 值捕获(拷贝)

auto capture_by_value = [x]() {

cout << " 值捕获 x = " << x << "\n";

// x++; // 错误!值捕获默认是const的

};

capture_by_value();

// 2. 引用捕获

auto capture_by_ref = [&y]() {

cout << " 引用捕获 y = " << y << "\n";

y++; // 可以修改

};

capture_by_ref();

cout << " 修改后 y = " << y << "\n";

// 3. 混合捕获

auto mixed_capture = [x, &y]() {

cout << " 混合捕获: x = " << x << ", y = " << y << "\n";

};

mixed_capture();

不使用mutable:值捕获的变量是const的

泛型Lambda (C++14)

// C++14: auto参数

auto print = [](auto x) {

cout << " 值: " << x << ", 类型: ";

if constexpr (is_same_v<decltype(x), int>)

cout << "int\n";

else if constexpr (is_same_v<decltype(x), double>)

cout << "double\n";

else if constexpr (is_same_v<decltype(x), string>)

cout << "string\n";

else

cout << "其他\n";

};

Lambda与STL算法

vector<int> nums = {5, 2, 8, 1, 9, 3, 7, 4, 6};

// for_each

cout << "\nfor_each打印平方:\n ";

for_each(nums.begin(), nums.end(), [](int n) {

cout << n * n << " ";

});

// accumulate with Lambda

int sum = 0;

for_each(nums.begin(), nums.end(), [&sum](int n) {

sum += n;

});

给Lambda 表达式起名字

// 定义Lambda表达式,命名为divide(赋值给auto变量)

auto divide = [](int a, int b) -> double {

// 把a转为double,避免整数除法(10/3=3),得到浮点数结果(3.333...)

return static_cast<double>(a) / b; };

// 调用Lambda,输出结果 cout << " divide(10, 3) = " << divide(10, 3) << "\n";

// 输出3.33333...

捕获this

class Counter {

private:

int count_; // 私有成员变量

public:

void demo() {

count_ = 10;

// Lambda想访问count_,但是count_是类的成员

// Lambda必须通过this指针来访问成员

auto lambda = [this]() {

cout << this->count_ << endl;

};

lambda(); // 调用这个Lambda表达式

}

};

异常安全与错误处理

并发编程

常用设计模式

相关推荐
C+-C资深大佬2 小时前
C++ 性能优化 专业详解
java·c++·性能优化
程序员老乔2 小时前
Java 新纪元 — JDK 25 + Spring Boot 4 全栈实战(三):虚拟线程2.0,电商秒杀场景下的并发革命
java·开发语言·spring boot
weixin_404157682 小时前
Java高级面试与工程实践问题集(四)
java·开发语言·面试
xyq20242 小时前
CSS 链接(Link)详解
开发语言
无限进步_2 小时前
【C++】单词反转算法详解:原地操作与边界处理
java·开发语言·c++·git·算法·github·visual studio
senijusene2 小时前
通信概念,51UART的使用,以及MODBUS的简单应用
c语言·开发语言·单片机·51单片机
吗~喽2 小时前
【C++】模板的两大特性
c++
王璐WL2 小时前
【C++】string类基础知识
开发语言·c++
笑鸿的学习笔记2 小时前
qt-C++语法笔记之Qt中的delete ui、ui的本质与Q_OBJECT
c++·笔记·qt