איטרטורים
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C++ של Coddy. שיעור 72 מתוך 104.
איטרטורים הם אובייקטים המשמשים כגשר בין מכלים לאלגוריתמים. הם מספקים דרך אחידה לגשת לאיברים בכל מכל, בלי קשר לאופן שבו המכל מאחסן את הנתונים שלו באופן פנימי. אפשר לחשוב על איטרטור כעל מצביע כללי שיודע לנוע בתוך מכל.
כל מכולה של STL מספקת את המתודות begin() ו-end(). האיטרטור begin() מצביע על האיבר הראשון, ואילו end() מצביע על מיקום אחד אחרי האיבר האחרון — זקיף שמסמן היכן לעצור:
#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 << " "; // בצע דה־רפרנס כדי לקבל את הערך
}
// פלט: 10 20 30
}מילת המפתח auto מפשטת באופן משמעותי הצהרות של איטרטורים:
for (auto it = nums.begin(); it != nums.end(); ++it) {
*it *= 2; // שנה את האיברים באמצעות האיטרטור
}
// nums מכיל כעת {20, 40, 60}איטרטורים נחלקים לקטגוריות שונות לפי היכולות שלהם. איטרטורים לגישה אקראית (כמו אלה של vector) תומכים בפעולות חשבון כגון it + 3 או it1 - it2.
איטרטורים דו־כיווניים (של list, map) יכולים לנוע קדימה ואחורה באמצעות ++ ו־--. איטרטורים קדימה יכולים לנוע בכיוון אחד בלבד.
למעבר בסדר הפוך, השתמשו ב־rbegin() וב־rend():
for (auto rit = nums.rbegin(); rit != nums.rend(); ++rit) {
std::cout << *rit << " "; // מדפיס בסדר הפוך
}אתגר
קלבואו נבנה מערכת למעקב אחר מלאי שמשתמשת באיטרטורים כדי לעבור על אוספים של פריטים ולשנות אותם. תתרגלו שימוש בסוגים שונים של איטרטורים כדי לנווט בנתונים בדרכים שונות.
תארגנו את הקוד בשני קבצים:
Inventory.h: הגדירו מחלקה בשםInventoryשמנהלת אוסף של כמויות פריטים המאוחסנות ב-std::vector<int>.על המחלקה לספק את המתודות הבאות:
addItem(int quantity): מוסיפה למלאי כמות של פריטprintForward(): משתמשת באיטרטורים עםbegin()ו-end()כדי להדפיס את כל הכמויות כשהן מופרדות ברווחים, ואחריהן תו שורה חדשהprintReverse(): משתמשת באיטרטורים הפוכים עםrbegin()ו-rend()כדי להדפיס את כל הכמויות בסדר הפוך, כשהן מופרדות ברווחים, ואחריהן תו שורה חדשהdoubleAll(): משתמשת באיטרטורים כדי לעבור על המערך ולהכפיל כל כמות במקומהgetTotal(): משתמשת באיטרטורים כדי לחשב ולהחזיר את סכום כל הכמויות
השתמשו במילת המפתח
autoבהצהרות האיטרטורים כדי לשמור על קוד נקי.main.cpp: קראו ארבעה ערכי קלט של מספרים שלמים (כל אחד בשורה נפרדת) שמייצגים כמויות של פריטים.צרו אובייקט
Inventoryוהוסיפו אליו את כל ארבע הכמויות. לאחר מכן הדגימו שימוש באיטרטורים באמצעות:- הדפסת
Forward:ולאחריה קריאה ל-printForward() - הדפסת
Reverse:ולאחריה קריאה ל-printReverse() - הדפסת
Total: <sum>באמצעותgetTotal() - קריאה ל-
doubleAll()כדי לשנות את הכמויות - הדפסת
After doubling:ולאחריה קריאה ל-printForward() - הדפסת
New total: <sum>באמצעותgetTotal()
- הדפסת
לדוגמה, עבור הקלטים 10, 25, 15 ו-30:
Forward: 10 25 15 30
Reverse: 30 15 25 10
Total: 80
After doubling: 20 50 30 60
New total: 160האתגר הזה מאפשר לכם לתרגל גם קריאת איברים באמצעות איטרטורים (לצורך הדפסה וסיכום) וגם שינוי איברים באמצעות איטרטורים (לצורך הכפלה). כמו כן, תראו כיצד איטרטורים הפוכים מאפשרים מעבר לאחור בצורה פשוטה, ללא צורך בשימוש באינדקסים.
נסו בעצמכם
#include <iostream>
#include "Inventory.h"
using namespace std;
int main() {
// קראו ארבעה מספרים שלמים מהקלט
int q1, q2, q3, q4;
cin >> q1;
cin >> q2;
cin >> q3;
cin >> q4;
// TODO: צרו אובייקט מסוג Inventory
// TODO: הוסיפו את כל ארבע הכמויות למלאי
// TODO: הדפיסו "Forward: " ואז קראו ל־printForward()
// TODO: הדפיסו "Reverse: " ואז קראו ל־printReverse()
// TODO: הדפיסו "Total: " ואחריו את התוצאה של getTotal()
// TODO: קראו ל־doubleAll() כדי לשנות את הכמויות
// TODO: הדפיסו "After doubling: " ואז קראו ל־printForward()
// TODO: הדפיסו "New total: " ואחריו את התוצאה של getTotal()
return 0;
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות OOP
קבצים חיצונייםבנייה וקומפילציה של C++קובצי Header וקובצי מקורמרחבי שמות והיקףמבוא ל-OOP ב-C++מחלקות לעומת אובייקטיםמצביע thisמתודות (פונקציות איבר)תכונות (חברי נתונים)יסודות הבנאים וההורסיםסיכום – מחשבון פשוט4מאפייני מחלקה
חברי מופע לעומת חברים סטטייםגטרים וסטריםפונקציות איבר קבועותמילת המפתח mutableמתודות ומשתנים סטטייםפונקציות ומחלקות ידידותסיכום – מנהל חשבונות בנק7ירושה
ירושה בסיסיתרמות גישה בירושהסדר הקריאות לבנאי ולמפרקדריסת מתודותפונקציות וירטואליות ו־VTableירושה מרובהירושה וירטואליתסיכום – היררכיית עובדים10סקירה כללית של STL
סקירה כללית והפילוסופיה של STLקונטיינרים של STLאיטרטוריםאלגוריתמים של STLפונקטורים וביטויי למבדהסיכום – תדירות מילים2ניהול זיכרון
זיכרון Stack לעומת Heapמצביעים והפניותזיכרון דינמי (new/delete)מצביעים חכמים ב-C++RAII ב-C++סיכום – מנהל מערכים דינמיים5כימוס
מצייני גישה ב-C++מצייני גישה לעומקהסתרת מידעמבנה לעומת מחלקהמחלקות מקוננות ופנימיותסיכום – מערכת רשומות תלמידים8רב־צורתיות
רב־צורתיות בזמן קומפילציה לעומת בזמן ריצההעמסת פונקציותפונקציות וירטואליות — מבט נוסףפונקציות וירטואליות טהורותמחלקות מופשטותתכנון ממשקים ב־C++המרה דינמית ו־RTTIסיכום — מחשבון צורות3בנאים והורסים
בנאי ברירת מחדלבנאי עם פרמטריםבנאי העתקהבנאי העברהרשימות אתחול בבנאיםבנאים מאציליםמעמיקים בנושא הורסיםכלל השלושה / החמישה / האפססיכום – מחלקת String6העמסת אופרטורים
מבוא להעמסת אופרטוריםהעמסת אופרטורים אריתמטייםהעמסת אופרטורי השוואהאופרטורי זרםהעמסת אופרטור השמההעמסת האופרטורים [] ו־()אופרטורים להמרת טיפוסיםסיכום – מחלקת Matrix9תבניות
תבניות פונקציהתבניות מחלקההתמחות תבניותתבניות ארגומנטים משתנותיסודות SFINAE ותכונות טיפוסיםסיכום – מכל גנריתרגלו בעצמכם: קומפיילר C++ אונליין