קישור מובנה
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C++ של Coddy. שיעור 88 מתוך 104.
קישור מובנה, שהוצג ב־C++17, מאפשר לפרק ערכים מרובים ממערכים, מזוגות, מטאפלים או ממבנים למשתנים נפרדים בעלי שמות, בהצהרה אחת. כך הקוד נקי וקריא יותר כשעובדים עם נתונים מורכבים.
התחביר משתמש ב־auto עם סוגריים מרובעים המכילים את שמות המשתנים החדשים:
#include <iostream>
#include <map>
#include <tuple>
int main() {
// פירוק זוג
std::pair<std::string, int> person{"Alice", 25};
auto [name, age] = person;
std::cout << name << " is " << age << "\n";
// פירוק tuple
std::tuple<int, double, char> data{42, 3.14, 'X'};
auto [num, pi, letter] = data;
// פירוק בלולאות for מבוססות טווח
std::map<std::string, int> scores{{"Bob", 90}, {"Carol", 85}};
for (const auto& [student, score] : scores) {
std::cout << student << ": " << score << "\n";
}
}קישורים מובְנים עובדים גם עם מערכים ועם מבנים מותאמים אישית שיש להם איברים ציבוריים:
struct Point {
double x;
double y;
};
Point getOrigin() { return {0.0, 0.0}; }
int main() {
auto [x, y] = getOrigin();
int arr[3] = {1, 2, 3};
auto [a, b, c] = arr;
}אפשר להשתמש ב-auto& או ב-const auto& כדי לקשור באמצעות הפניה, וכך להימנע מהעתקות ולאפשר לשנות את הערכים המקוריים כשצריך. התכונה הזו שימושית במיוחד בעת איטרציה על מכלים של STL או טיפול בפונקציות שמחזירות כמה ערכים.
אתגר
קלבואו נבנה מנתח ציונים של תלמידים שמציג את העוצמה של קישור מובנה. תיצרו מערכת שמעבדת רשומות של תלמידים ונתוני קורסים, תוך שימוש בקישור מובנה כדי לפרק בקלות זוגות, tuples ומבנים לאורך הקוד שלכם.
תארגנו את הקוד שלכם בשלושה קבצים:
Student.h: הגדירו מבנהStudentעם איברים ציבוריים עבור שם התלמיד (std::string), מספר מזהה (int) וממוצע ציונים (double). צרו גם פונקציה בשםcreateStudentשמקבלת שם, מספר מזהה וממוצע ציונים, ומחזירה מבנהStudent.GradeUtils.h: צרו פונקציות שירות לעיבוד ציונים.הגדירו פונקציה
getGradeInfoשמקבלת ציון מספרי (מספר שלם) ומחזירהstd::tupleשמכיל שלושה ערכים: ציון באות (std::string), נקודות הציון (double) והאם הציון עובר (bool). השתמשו בסולם הציונים הבא:- 90 ומעלה: "A", 4.0, true
- 80-89: "B", 3.0, true
- 70-79: "C", 2.0, true
- 60-69: "D", 1.0, true
- מתחת ל-60: "F", 0.0, false
הגדירו גם פונקציה
makeScorePairשמקבלת שם קורס (std::string) וציון (int), ומחזירהstd::pairשל הערכים האלה.main.cpp: קראו ארבעה קלטים:- שם התלמיד (מחרוזת)
- מספר מזהה של התלמיד (מספר שלם)
- שם הקורס (מחרוזת)
- ציון (מספר שלם)
השתמשו בקישור מובנה לאורך הפונקציה הראשית שלכם:
- קראו ל-
createStudentעם השם, מספר המזהה וערך ממוצע ציונים זמני של 0.0. השתמשו בקישור מובנה כדי לפרק את המבנה שהוחזר למשתנים נפרדים, ואז הדפיסו:Student: [name] (ID: [id]) - קראו ל-
makeScorePairעם שם הקורס והציון. השתמשו בקישור מובנה כדי לפרק את הזוג, ואז הדפיסו:Course: [course], Score: [score] - קראו ל-
getGradeInfoעם הציון. השתמשו בקישור מובנה כדי לפרק את שלושת איברי ה-tuple, ואז הדפיסו:(הדפיסו "yes" אם הציון עובר הוא true, ו-"no" אם הוא false)Grade: [letter] Points: [points] Passing: [yes/no]
לדוגמה, עבור הקלטים Alice, 1001, Math ו-85:
Student: Alice (ID: 1001)
Course: Math, Score: 85
Grade: B
Points: 3
Passing: yesעבור הקלטים Bob, 2002, Physics ו-55:
Student: Bob (ID: 2002)
Course: Physics, Score: 55
Grade: F
Points: 0
Passing: noזכרו לכלול את <tuple> ואת <utility> במקומות הנדרשים. התובנה המרכזית היא שקישור מובנה מאפשר לפרק טיפוסים מורכבים, זוגות, tuples ומבנים למשתנים בעלי שמות בהצהרה יחידה וקריאה.
נסו בעצמכם
#include <iostream>
#include <string>
#include "Student.h"
#include "GradeUtils.h"
int main() {
// קראו את הקלטים
std::string studentName;
int studentId;
std::string courseName;
int score;
std::cin >> studentName;
std::cin >> studentId;
std::cin >> courseName;
std::cin >> score;
// TODO: קראו ל־createStudent עם השם, המזהה ו־GPA זמני של 0.0
// השתמשו בקשירות מובנות כדי לפרק את ה־struct: auto [name, id, gpa] = ...
// הדפיסו: Student: [name] (ID: [id])
// TODO: קראו ל־makeScorePair עם שם הקורס והציון
// השתמשו בקשירות מובנות כדי לפרק את הזוג: auto [course, sc] = ...
// הדפיסו: Course: [course], Score: [score]
// TODO: קראו ל־getGradeInfo עם הציון
// השתמשו בקשירות מובנות כדי לפרק את ה־tuple: auto [letter, points, passing] = ...
// הדפיסו:
// Grade: [letter]
// Points: [points]
// עובר: [yes/no] (הדפס "yes" אם passing הוא true, ו-"no" אם הוא false)
return 0;
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות OOP
קבצים חיצונייםבנייה וקומפילציה של C++קובצי Header וקובצי מקורמרחבי שמות והיקףמבוא ל-OOP ב-C++מחלקות לעומת אובייקטיםמצביע thisמתודות (פונקציות איבר)תכונות (חברי נתונים)יסודות הבנאים וההורסיםסיכום – מחשבון פשוט4מאפייני מחלקה
חברי מופע לעומת חברים סטטייםגטרים וסטריםפונקציות איבר קבועותמילת המפתח mutableמתודות ומשתנים סטטייםפונקציות ומחלקות ידידותסיכום – מנהל חשבונות בנק7ירושה
ירושה בסיסיתרמות גישה בירושהסדר הקריאות לבנאי ולמפרקדריסת מתודותפונקציות וירטואליות ו־VTableירושה מרובהירושה וירטואליתסיכום – היררכיית עובדים2ניהול זיכרון
זיכרון Stack לעומת Heapמצביעים והפניותזיכרון דינמי (new/delete)מצביעים חכמים ב-C++RAII ב-C++סיכום – מנהל מערכים דינמיים5כימוס
מצייני גישה ב-C++מצייני גישה לעומקהסתרת מידעמבנה לעומת מחלקהמחלקות מקוננות ופנימיותסיכום – מערכת רשומות תלמידים8רב־צורתיות
רב־צורתיות בזמן קומפילציה לעומת בזמן ריצההעמסת פונקציותפונקציות וירטואליות — מבט נוסףפונקציות וירטואליות טהורותמחלקות מופשטותתכנון ממשקים ב־C++המרה דינמית ו־RTTIסיכום — מחשבון צורות3בנאים והורסים
בנאי ברירת מחדלבנאי עם פרמטריםבנאי העתקהבנאי העברהרשימות אתחול בבנאיםבנאים מאציליםמעמיקים בנושא הורסיםכלל השלושה / החמישה / האפססיכום – מחלקת String6העמסת אופרטורים
מבוא להעמסת אופרטוריםהעמסת אופרטורים אריתמטייםהעמסת אופרטורי השוואהאופרטורי זרםהעמסת אופרטור השמההעמסת האופרטורים [] ו־()אופרטורים להמרת טיפוסיםסיכום – מחלקת Matrix9תבניות
תבניות פונקציהתבניות מחלקההתמחות תבניותתבניות ארגומנטים משתנותיסודות SFINAE ותכונות טיפוסיםסיכום – מכל גנרי12תכונות מודרניות ב־C++
סמנטיקת העברה ו־rvaluesהעברה מושלמתביטויי Lambda לעומקstd::function ו־std::bindconstexpr ו־constevalקישור מובנהoptional, variant, anyתרגלו בעצמכם: קומפיילר C++ אונליין