pair、struct 和 enum class
一个商品有名字、数量、价格;一个学生有名字和分数。几样东西总是一起出现,就把它们放在一起。最简单的是 std::pair:正好两样,用 .first 和 .second 取出来,和上一课 map 里的每一对一样。要 #include <utility>。
1#include <iostream>2#include <string>3#include <utility>4 5int main() {6 std::pair<std::string, int> best{"小林", 95};7 std::cout << best.first << " 考了 " << best.second << " 分\n";8 best.second = 98;9 std::pair<std::string, int> next = std::make_pair("小王", 90);10 std::cout << best.second << " " << next.first << '\n';11 return 0;12}
小林 考了 95 分 98 小王
std::pair<std::string, int>:第一样是字符串,第二样是 int。std::make_pair("小王", 90) 用括号里的两个值做出一个 pair,不用写尖括号里的类型;下面的函数就用它返回结果。
pair:一次返回两个值
函数只能返回一个值。要返回两个,就返回一个 pair:
1#include <iostream>2#include <utility>3#include <vector>4 5std::pair<int, int> low_high(const std::vector<int>& temps) {6 int low = temps[0];7 int high = temps[0];8 for (int t : temps) {9 if (t < low) {10 low = t;11 }12 if (t > high) {13 high = t;14 }15 }16 return std::make_pair(low, high);17}18 19int main() {20 std::vector<int> week{18, 23, 16, 21, 19};21 std::pair<int, int> r = low_high(week);22 std::cout << "最低 " << r.first << ",最高 " << r.second << '\n';23 return 0;24}
最低 16,最高 23
两个 pair 也能比大小:先比 .first,一样再比 .second。所以一个装 pair 的 vector 可以直接 sort:
排好以后,v[1] 是哪一对?
1#include <algorithm>2#include <iostream>3#include <utility>4#include <vector>5 6int main() {7 std::vector<std::pair<int, int>> v{{2, 9}, {1, 5}, {2, 3}};8 std::sort(v.begin(), v.end());9 std::cout << v[1].first << " " << v[1].second << '\n';10 return 0;11}
先比 .first:{1, 5} 最小,排第一。剩下两对的 .first 都是 2,再比 .second:3 比 9 小,所以 {2, 3} 排第二。
struct:自己的类型
pair 只有两样,名字也只叫 first 和 second,看不出是什么。三样以上,或者想起清楚的名字,就用 struct 自己定义一个类型。里面的变量叫成员,用 . 取:
1#include <iostream>2#include <string>3 4struct Item {5 std::string name;6 int count;7 double price;8};9 10int main() {11 Item pen{"圆珠笔", 3, 2.5};12 pen.count += 2;13 std::cout << pen.name << ":" << pen.count << " 支,";14 std::cout << "共 " << pen.count * pen.price << " 元\n";15 return 0;16}
圆珠笔:5 支,共 12.5 元
struct Item { ... }; 定义了一个新类型 Item,之后就能像 int 一样用它声明变量。Item pen{"圆珠笔", 3, 2.5} 按成员的顺序给值。点单步,看 pen 显示成三个字段。
定义 struct 的右花括号后面要有分号,这是最常忘的一个:
1#include <iostream>2#include <string>3 4struct Item {5 std::string name;6 int count;7}8 9int main() {10 Item cup{"杯子", 4};11 std::cout << cup.name << '\n';12 return 0;13}
main.cpp:7:2: error: expected ';' after struct definition
7 | }
| ^
| ;g++ 指着第 7 行的 } 说:expected ';' after struct definition。
vector 里放 struct
struct 和 vector 放在一起,就是一张表:每个元素是一行,每个成员是一列。传给函数也和别的大东西一样,用 const Item&:
1#include <iostream>2#include <string>3#include <vector>4 5struct Item {6 std::string name;7 int count;8 double price;9};10 11double value(const Item& item) {12 return item.count * item.price;13}14 15int main() {16 std::vector<Item> stock{{"圆珠笔", 5, 2.5}, {"笔记本", 3, 8.0}, {"橡皮", 10, 1.5}};17 double total = 0;18 for (const auto& item : stock) {19 std::cout << item.name << ":" << value(item) << " 元\n";20 total += value(item);21 }22 std::cout << "合计:" << total << " 元\n";23 return 0;24}
圆珠笔:12.5 元 笔记本:24 元 橡皮:15 元 合计:51.5 元
花括号里每个 {...} 是一个 Item。
按成员排序
std::sort 不知道两个 Item 谁大谁小。你写一个函数告诉它:两个参数,第一个应该排在前面就返回 true。把函数名作为第三个参数交给 sort:
1#include <algorithm>2#include <iostream>3#include <string>4#include <vector>5 6struct Student {7 std::string name;8 int score;9};10 11bool higher_score(const Student& a, const Student& b) {12 return a.score > b.score;13}14 15int main() {16 std::vector<Student> cls{{"小林", 82}, {"小王", 95}, {"小张", 77}};17 std::sort(cls.begin(), cls.end(), higher_score);18 for (const auto& s : cls) {19 std::cout << s.name << " " << s.score << '\n';20 }21 return 0;22}
小王 95 小林 82 小张 77
higher_score 后面没有括号:这里不是调用它,是把它交给 sort,让 sort 需要比的时候自己去调用。用 > 是分数高的在前,用 < 就是低的在前。第 22 课会学 lambda,那时可以把比较直接写在 sort 的括号里。
enum class:给选项起名字
有些值只能是几个选项之一:尺码是小、中、大,订单是待付款、已发货、已送达。用 0、1、2 表示,过几天就忘了 2 是什么。enum class 给每个选项起名字:
1#include <iostream>2 3enum class Size { Small, Medium, Large };4 5int main() {6 Size s = Size::Large;7 int code = s;8 std::cout << code << '\n';9 return 0;10}
main.cpp: In function 'int main()':
main.cpp:7:16: error: cannot convert 'Size' to 'int' in initialization
7 | int code = s;
| ^
| |
| Sizeenum class Size 定义了一个类型,它的值只能是 Size::Small、Size::Medium、Size::Large。它们不是 int,所以 int code = s; 编译不过:cannot convert 'Size' to 'int'。这是故意的:尺码不该被当成数随便加减。
真要它对应的数,就用 static_cast<int>:
这段程序显示什么?
1#include <iostream>2 3enum class Size { Small, Medium, Large };4 5int main() {6 Size s = Size::Large;7 std::cout << static_cast<int>(s) << '\n';8 return 0;9}
不写数的时候,第一个选项是 0,后面依次加 1:Small 是 0,Medium 是 1,Large 是 2。
switch 配 enum class
enum class 和 switch 是一对好搭档:每个 case 写一个选项,读起来就像一张说明:
1#include <iostream>2#include <string>3 4enum class Status { Unpaid, Shipped, Delivered };5 6std::string describe(Status s) {7 switch (s) {8 case Status::Unpaid:9 return "待付款";10 case Status::Shipped:11 return "已发货";12 case Status::Delivered:13 return "已送达";14 }15 return "不明";16}17 18int main() {19 Status order = Status::Unpaid;20 std::cout << describe(order) << '\n';21 order = Status::Shipped;22 std::cout << describe(order) << '\n';23 return 0;24}
待付款 已发货
每个 case 都直接 return 了,不用 break。switch 后面那个 return "不明"; 让函数在任何情况下都有返回值。
小技巧: 用 g++ -Wall 编译时,switch 漏写了某个选项,g++ 会提醒你。以后给 Status 加一个新选项,编译器就帮你找出所有要改的地方。
练一练
写好代码,点检查。提示随便看,实在想不出来再看答案。
最贵的一件
✓写好 most_expensive:走一遍 items,把价格最高的那件交回去。main 已经写好了,会对两组商品各问一次。
最贵:耳机 199 最贵:锅 268
1#include <iostream>2#include <string>3#include <vector>4 5struct Item {6 std::string name;7 int price;8};9 10Item most_expensive(const std::vector<Item>& items) {11 Item best = items[0];12 13 return best;14}15 16int main() {17 std::vector<Item> desk{{"鼠标", 89}, {"耳机", 199}, {"键盘", 159}};18 std::vector<Item> kitchen{{"水壶", 129}, {"刀", 99}, {"锅", 268}};19 Item a = most_expensive(desk);20 std::cout << "最贵:" << a.name << " " << a.price << '\n';21 Item b = most_expensive(kitchen);22 std::cout << "最贵:" << b.name << " " << b.price << '\n';23 return 0;24}
按身高排队
✓写一个比较函数,把 kids 按身高从矮到高排好,再一行一个显示名字和身高。
豆豆 121 乐乐 128 果果 134
1#include <algorithm>2#include <iostream>3#include <string>4#include <vector>5 6struct Kid {7 std::string name;8 int height;9};10 11int main() {12 std::vector<Kid> kids{{"乐乐", 128}, {"豆豆", 121}, {"果果", 134}};13 14 return 0;15}
修好它:尺码不是数
✓这段程序编译不过。改好它,让它显示 尺码编号:1。
尺码编号:1
1#include <iostream>2 3enum class Size { Small, Medium, Large };4 5int main() {6 Size s = Size::Medium;7 int code = s;8 std::cout << "尺码编号:" << code << '\n';9 return 0;10}
这一课学会了
std::pair<A, B>装两样,用.first、.second取;std::make_pair自己推出类型;函数可以返回pair。pair先比.first再比.second,所以能直接排序。struct定义自己的类型,成员用.取;右花括号后面要有分号。std::vector<Item>是一张表;传给函数用const Item&。- 按成员排序:写一个返回
bool的比较函数,交给std::sort当第三个参数。 enum class给选项起名字(Size::Large),不能直接当int,要static_cast<int>;和switch一起用最清楚。