- C++
C++ STL 容器 vector 重载运算符教程
- 2025-5-29 11:57:23 @
C++ STL 容器 vector 重载运算符教程
1. vector 简介
定义:vector 是 C++ 标准库中的动态数组容器,支持随机访问和动态扩容。
头文件:
#include <vector>
声明:
std::vector<数据类型> 变量名;
示例:
std::vector<int> numbers; // 空 vector
std::vector<double> scores(5, 0.0); // 包含5个0.0的vector
2. vector 重载的运算符
vector 容器重载了多个运算符,使其使用起来更像普通数组:
运算符 | 功能描述 |
---|---|
[] |
访问指定位置的元素 |
= |
赋值运算符 |
== |
判断两个 vector 是否相等 |
!= |
判断两个 vector 是否不等 |
< |
比较两个 vector 的大小 |
<= |
|
> |
|
>= |
|
<< |
输出 vector 的元素(需自定义) |
3. 下标运算符 []
功能:访问 vector 中指定位置的元素。
示例:
#include <vector>
#include <iostream>
int main() {
std::vector<int> numbers = {10, 20, 30, 40, 50};
// 使用[]访问元素
std::cout << "第一个元素: " << numbers[0] << std::endl; // 输出: 10
// 修改元素
numbers[2] = 300;
std::cout << "修改后的第三个元素: " << numbers[2] << std::endl; // 输出: 300
return 0;
}
注意:[]
不进行边界检查,使用超出范围的索引会导致未定义行为。
4. 赋值运算符 =
功能:将一个 vector 的内容复制给另一个 vector。
示例:
#include <vector>
#include <iostream>
int main() {
std::vector<int> source = {1, 2, 3};
std::vector<int> destination;
// 使用赋值运算符
destination = source;
// 输出 destination 的内容
for (int num : destination) {
std::cout << num << " "; // 输出: 1 2 3
}
std::cout << std::endl;
return 0;
}
注意:赋值后两个 vector 是独立的,修改一个不会影响另一个。
5. 比较运算符
vector 支持所有关系运算符 (==
, !=
, <
, <=
, >
, >=
),比较规则如下:
- 按元素顺序逐个比较
- 如果所有元素都相等且大小相同,则
==
返回 true - 第一个不相等元素的比较结果决定
<
或>
的结果
示例:
#include <vector>
#include <iostream>
int main() {
std::vector<int> a = {1, 2, 3};
std::vector<int> b = {1, 2, 3};
std::vector<int> c = {1, 2, 4};
std::cout << std::boolalpha; // 输出 true/false 而非 1/0
std::cout << "a == b: " << (a == b) << std::endl; // 输出: true
std::cout << "a == c: " << (a == c) << std::endl; // 输出: false
std::cout << "a < c: " << (a < c) << std::endl; // 输出: true
std::cout << "a > c: " << (a > c) << std::endl; // 输出: false
return 0;
}
6. 自定义重载运算符
除了 vector 内置的运算符重载,我们还可以自定义重载其他运算符。
示例1:重载 <<
运算符用于输出 vector
#include <vector>
#include <iostream>
// 重载<<运算符
template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& vec) {
os << "[";
for (size_t i = 0; i < vec.size(); ++i) {
os << vec[i];
if (i != vec.size() - 1) {
os << ", ";
}
}
os << "]";
return os;
}
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
// 使用重载的<<运算符输出vector
std::cout << "numbers: " << numbers << std::endl; // 输出: numbers: [1, 2, 3, 4, 5]
return 0;
}
示例2:重载 +
运算符用于连接两个 vector
#include <vector>
#include <iostream>
// 重载+运算符
template <typename T>
std::vector<T> operator+(const std::vector<T>& a, const std::vector<T>& b) {
std::vector<T> result = a;
result.insert(result.end(), b.begin(), b.end());
return result;
}
int main() {
std::vector<int> a = {1, 2, 3};
std::vector<int> b = {4, 5, 6};
// 使用重载的+运算符连接两个vector
std::vector<int> c = a + b;
// 输出结果
for (int num : c) {
std::cout << num << " "; // 输出: 1 2 3 4 5 6
}
std::cout << std::endl;
return 0;
}
7. 安全访问:at() 方法
虽然 []
运算符很方便,但它不进行边界检查。为了安全访问元素,可以使用 at()
方法:
#include <vector>
#include <iostream>
int main() {
std::vector<int> numbers = {10, 20, 30};
try {
// 安全访问,会进行边界检查
std::cout << numbers.at(5) << std::endl;
} catch (const std::out_of_range& e) {
std::cout << "错误: " << e.what() << std::endl; // 输出: 错误: vector::_M_range_check: __n (which is 5) >= this->size() (which is 3)
}
return 0;
}
8. 性能考虑
-
[]
和at()
的性能差异:[]
直接访问内存,无额外开销at()
会进行边界检查,有轻微性能损失
-
赋值运算符
=
的性能:- 对于大型 vector,复制操作可能较慢
- 考虑使用移动语义 (
std::move
) 避免复制
总结
vector 通过重载运算符提供了类似普通数组的使用方式,同时保留了动态扩容的能力。常用的重载运算符包括:
[]
用于元素访问=
用于赋值- 关系运算符 (
==
,!=
,<
, 等) 用于比较
此外,我们还可以自定义重载其他运算符(如 <<
和 +
)以增强 vector 的功能。使用时应注意 []
和 at()
的区别,根据需要选择安全访问或性能优先的方式。
1 条评论
-
admin SU @ 2025-5-29 11:59:16
🧠 C++ STL 容器
std::vector
重载运算符教程✅ 通俗易懂讲解如何为 vector 中的自定义类型(类或结构体)重载运算符
📚 涵盖:==
,!=
,<
,>
,<<
,+
等常用运算符
🕒 当前时间:2025年5月29日,星期四11时47分
📘 目录
- 🧱 什么是运算符重载?
- 🎯 为什么需要为
std::vector
中的元素重载运算符? - 🛠️ 如何为结构体重载常见运算符
==
和!=
<
、>
、<=
、>=
+
、-
等数学运算符<<
(流输出)
- 🧩 在
std::vector
中使用重载后的结构体 - 🧪 示例项目:学生信息排序与比较
- 🧠 小贴士 & 常见错误
- 📌 总结
1️⃣ 🧱 什么是运算符重载?
在 C++ 中,你可以通过 运算符重载(Operator Overloading) 来为自定义类型(如结构体、类)定义类似内置类型的运算行为。
例如:
Point a(1, 2), b(3, 4); Point c = a + b; // 自定义加法逻辑
2️⃣ 🎯 为什么要为 vector 中的元素重载运算符?
当你把一个自定义结构体放入
std::vector
后,常常需要:- 排序(使用
std::sort
)➡️ 需要<
运算符 - 查找(使用
std::find
)➡️ 需要==
运算符 - 输出调试信息 ➡️ 需要
<<
流运算符 - 计算总和、差值等 ➡️ 需要
+
,-
运算符
如果不重载这些运算符,编译器就不知道怎么处理这些操作!
3️⃣ 🛠️ 如何为结构体重载常见运算符
🔹 结构体示例
我们以一个
Student
结构体为例:struct Student { std::string name; int age; };
✅ 1. 重载
==
和!=
用于判断两个对象是否相等。
bool operator==(const Student& s1, const Student& s2) { return s1.name == s2.name && s1.age == s2.age; } bool operator!=(const Student& s1, const Student& s2) { return !(s1 == s2); }
🔹 使用场景:
std::find
std::vector<Student> students = {{"Alice", 20}, {"Bob", 22}}; auto it = std::find(students.begin(), students.end(), Student{"Alice", 20});
✅ 2. 重载
<
、>
、<=
、>=
常用于排序,尤其是
std::sort
bool operator<(const Student& s1, const Student& s2) { if (s1.name != s2.name) return s1.name < s2.name; return s1.age < s2.age; }
🔹 使用场景:
std::sort
std::sort(students.begin(), students.end());
✅ 3. 重载
+
或其他数学运算符例如将两个学生的年龄相加:
Student operator+(const Student& s1, const Student& s2) { return Student{"Combined", s1.age + s2.age}; }
🔹 使用方式:
Student sum = students[0] + students[1];
✅ 4. 重载
<<
(输出运算符)方便打印调试信息:
std::ostream& operator<<(std::ostream& os, const Student& s) { os << "Student{name: \"" << s.name << "\", age: " << s.age << "}"; return os; }
🔹 使用方式:
for (const auto& s : students) { std::cout << s << std::endl; }
4️⃣ 🧩 在
std::vector
中使用重载后的结构体✅ 示例代码汇总:
#include <iostream> #include <vector> #include <algorithm> #include <string> struct Student { std::string name; int age; }; // == 运算符 bool operator==(const Student& s1, const Student& s2) { return s1.name == s2.name && s1.age == s2.age; } // < 运算符(用于排序) bool operator<(const Student& s1, const Student& s2) { if (s1.name != s2.name) return s1.name < s2.name; return s1.age < s2.age; } // << 运算符 std::ostream& operator<<(std::ostream& os, const Student& s) { os << "Student{name: \"" << s.name << "\", age: " << s.age << "}"; return os; } int main() { std::vector<Student> students = { {"Charlie", 21}, {"Alice", 20}, {"Bob", 22} }; // 排序 std::sort(students.begin(), students.end()); // 查找 Student target{"Alice", 20}; auto it = std::find(students.begin(), students.end(), target); if (it != students.end()) { std::cout << "Found student: " << *it << std::endl; } else { std::cout << "Student not found!" << std::endl; } return 0; }
5️⃣ 🧪 示例项目:学生信息排序与比较
你可以在 GitHub 创建一个项目来练习以下内容:
功能 所需重载 显示所有学生 <<
按姓名/年龄排序 <
判断两个学生是否相同 ==
求多个学生平均年龄 +
、/
6️⃣ 🧠 小贴士 & 常见错误
✅ 推荐做法:
- 使用
friend
函数进行类内部运算符重载(如果是class
而不是struct
)。 - 对于复杂排序,考虑使用 lambda 表达式传入比较函数。
- 使用
std::tie
简化多重字段比较。
❌ 常见错误:
- 忘记返回
bool
- 没有考虑所有字段导致比较错误
- 混淆成员函数与非成员函数(如
operator<<
必须是非成员函数)
7️⃣ 📌 总结
运算符 用途 是否必须 ==
/!=
比较、查找 ✅ <
/>
排序、集合容器 <<
输出调试信息 ❗建议 +
/-
数学计算 可选
📄 下一步学习建议
- 学习
std::map
、std::set
的使用(依赖<
运算符) - 探索模板泛型下的运算符重载
- 学习智能指针与自定义容器结合使用
- 实践设计模式(如工厂模式创建 vector 元素)
- 1