Bộ lặp
Thuộc phần Lập trình hướng đối tượng trong hành trình C++ của Coddy. Bài học 72 trên 104.
Bộ lặp (iterator) là các đối tượng đóng vai trò cầu nối giữa vùng chứa (container) và thuật toán (algorithm). Chúng cung cấp một cách truy cập thống nhất vào các phần tử trong mọi vùng chứa, bất kể vùng chứa đó lưu trữ dữ liệu nội bộ như thế nào. Hãy xem bộ lặp như một con trỏ tổng quát biết cách di chuyển qua vùng chứa.
Mọi vùng chứa STL đều cung cấp các phương thức begin() và end(). Trình lặp begin() trỏ đến phần tử đầu tiên, còn end() trỏ đến vị trí ngay sau phần tử cuối cùng, một dấu mốc cho biết cần dừng ở đâu:
#include <vector>
#include <iostream>
int main() {
std::vector<int> nums = {10, 20, 30};
for (std::vector<int>::iterator it = nums.begin(); it != nums.end(); ++it) {
std::cout << *it << " "; // Giải tham chiếu để lấy giá trị
}
// Đầu ra: 10 20 30
}Từ khóa auto giúp khai báo iterator đơn giản hơn đáng kể:
for (auto it = nums.begin(); it != nums.end(); ++it) {
*it *= 2; // Thay đổi các phần tử (element) qua bộ lặp (iterator)
}
// nums giờ là {20, 40, 60}Bộ lặp có nhiều loại khác nhau tùy theo khả năng. Bộ lặp truy cập ngẫu nhiên (như bộ lặp từ vector) hỗ trợ các phép toán số học như it + 3 hoặc it1 - it2.
Bộ lặp hai chiều (từ list, map) có thể di chuyển tiến và lùi bằng ++ và --. Bộ lặp tiến chỉ có thể di chuyển theo một hướng.
Để duyệt ngược, hãy dùng rbegin() và rend():
for (auto rit = nums.rbegin(); rit != nums.rend(); ++rit) {
std::cout << *rit << " "; // In ra theo thứ tự ngược lại
}Thử thách
DễHãy xây dựng hệ thống theo dõi hàng tồn kho dùng trình lặp để duyệt và thao tác với tập hợp các mặt hàng. Bạn sẽ luyện tập cách dùng các loại trình lặp khác nhau để duyệt dữ liệu theo nhiều cách.
Bạn sẽ sắp xếp code trong hai tệp:
Inventory.h: Định nghĩa lớpInventoryquản lý tập hợp số lượng mặt hàng được lưu trongstd::vector<int>.Lớp của bạn cần có các phương thức sau:
addItem(int quantity): thêm số lượng một mặt hàng vào khoprintForward(): dùng trình lặp vớibegin()vàend()để in tất cả số lượng, cách nhau bằng dấu cách và theo sau là ký tự xuống dòngprintReverse(): dùng trình lặp ngược vớirbegin()vàrend()để in tất cả số lượng theo thứ tự ngược, cách nhau bằng dấu cách và theo sau là ký tự xuống dòngdoubleAll(): dùng trình lặp để duyệt mảng và nhân đôi tại chỗ từng số lượnggetTotal(): dùng trình lặp để tính và trả về tổng tất cả số lượng
Dùng từ khóa
autokhi khai báo trình lặp để code gọn gàng hơn.main.cpp: Đọc bốn đầu vào số nguyên, mỗi số trên một dòng riêng, biểu thị số lượng mặt hàng.Tạo một đối tượng
Inventoryvà thêm cả bốn số lượng vào đó. Sau đó, minh họa cách dùng trình lặp bằng cách:- In
Forward:, sau đó gọiprintForward() - In
Reverse:, sau đó gọiprintReverse() - In
Total: <sum>bằnggetTotal() - Gọi
doubleAll()để thay đổi các số lượng - In
After doubling:, sau đó gọiprintForward() - In
New total: <sum>bằnggetTotal()
- In
Ví dụ, với đầu vào 10, 25, 15 và 30:
Forward: 10 25 15 30
Reverse: 30 15 25 10
Total: 80
After doubling: 20 50 30 60
New total: 160Thử thách này giúp bạn luyện tập cả việc đọc phần tử thông qua trình lặp (để in và tính tổng) lẫn thay đổi phần tử thông qua trình lặp (để nhân đôi). Bạn cũng sẽ thấy trình lặp ngược giúp việc duyệt theo chiều ngược lại trở nên đơn giản mà không cần thao tác với chỉ số.
Tự làm thử
#include <iostream>
#include "Inventory.h"
using namespace std;
int main() {
// Đọc bốn số nguyên đầu vào
int q1, q2, q3, q4;
cin >> q1;
cin >> q2;
cin >> q3;
cin >> q4;
// TODO: Tạo một đối tượng Inventory
// TODO: Thêm cả bốn số lượng vào kho
// TODO: In ra "Forward: " rồi gọi printForward()
// TODO: In ra "Reverse: " rồi gọi printReverse()
// TODO: In ra "Total: " rồi in kết quả của getTotal()
// TODO: Gọi doubleAll() để thay đổi các số lượng
// TODO: In ra "After doubling: " rồi gọi printForward()
// TODO: In ra "New total: " rồi in kết quả của getTotal()
return 0;
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng về OOP
Tệp bên ngoàiBiên dịch và tạo bản dựng C++Tệp header và tệp nguồnNamespace và phạm viGiới thiệu về OOP trong C++Lớp và đối tượngCon trỏ thisPhương thức (hàm thành viên)Thuộc tính (dữ liệu thành viên)Cơ bản về hàm khởi tạo và hàm hủyÔn tập: máy tính đơn giản4Thuộc tính của lớp
Thành viên đối tượng và thành viên tĩnhHàm truy xuất và hàm thiết lậpHàm thành viên hằngTừ khóa mutablePhương thức và biến tĩnhHàm và lớp bạnÔn tập: Trình quản lý tài khoản ngân hàng7Kế thừa
Kế thừa cơ bảnMức truy cập trong kế thừaThứ tự gọi hàm khởi tạo và hàm hủyGhi đè phương thứcHàm ảo và VTableĐa kế thừaKế thừa ảoÔn tập: hệ phân cấp nhân viên2Quản lý bộ nhớ
Bộ nhớ ngăn xếp và heapCon trỏ và tham chiếuBộ nhớ động (new/delete)Con trỏ thông minh trong C++RAII trong C++Ôn tập: Trình quản lý mảng động5Tính đóng gói
Phạm vi truy cập trong C++Tìm hiểu sâu về phạm vi truy cậpẨn thông tinStruct và lớpLớp lồng nhau và lớp bên trongÔn tập: hệ thống hồ sơ sinh viên8Đa hình
Đa hình lúc biên dịch và khi chạyNạp chồng hàmÔn lại hàm ảoHàm ảo thuần túyLớp trừu tượngThiết kế interface trong C++Ép kiểu động và RTTIÔn tập: Máy tính hình học3Hàm khởi tạo và hàm hủy
Hàm khởi tạo mặc địnhHàm khởi tạo có tham sốHàm khởi tạo sao chépHàm khởi tạo di chuyểnDanh sách khởi tạoHàm khởi tạo ủy quyềnTìm hiểu sâu về hàm hủyQuy tắc 3 / 5 / 0Ôn tập: lớp chuỗi6Nạp chồng toán tử
Giới thiệu về nạp chồng toán tửNạp chồng toán tử số họcNạp chồng toán tử so sánhToán tử luồngNạp chồng toán tử gánNạp chồng toán tử [] và ()Toán tử chuyển đổi kiểuÔn tập: lớp ma trận9Mẫu
Mẫu hàmMẫu lớpChuyên biệt hóa mẫuMẫu biến tham sốCơ bản về SFINAE và đặc điểm kiểuÔn tập: vùng chứa tổng quátTự luyện tập: Trình biên dịch C++ online