רשימות אתחול בבנאים
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C++ של Coddy. שיעור 22 מתוך 104.
ראית את תחביר הנקודתיים בשיעורים קודמים, כמו Player(std::string n, int h) : name(n), health(h) {}. זה נקרא רשימת אתחול של איברים, וזו הדרך המועדפת לאתחל איברים ב־C++.
רשימת האתחול מופיעה אחרי רשימת הפרמטרים של הבנאי, ומתחילה בנקודתיים. כל איבר מאותחל ישירות בערכו, כשהאיברים מופרדים בפסיקים:
class Rectangle {
int width;
int height;
const int id;
int& reference;
public:
Rectangle(int w, int h, int i, int& r)
: width(w), height(h), id(i), reference(r) {
// גוף הבנאי (יכול להיות ריק)
}
};למה להשתמש ברשימות אתחול במקום בהשמה בגוף הבנאי? בהשמה, האיברים מאותחלים תחילה כברירת מחדל ואז מקבלים ערכים חדשים. ברשימות אתחול, האיברים נבנים ישירות עם הערכים הנכונים — יעיל יותר ולעיתים אף הכרחי.
חברים מסוימים חייבים להיות מאותחלים באמצעות הרשימה:
- חברי
const— אי אפשר להקצות להם ערך לאחר הבנייה
- חברי הפניה - חייבים להיות מקושרים בעת האתחול
- חברים ללא בנאים כברירת מחדל
class Player {
const int maxHealth; // חובה להשתמש ברשימת אתחול
std::string name;
public:
// זה עובד
Player(int max, std::string n) : maxHealth(max), name(n) {}
// הקוד הזה לא יעבור קומפילציה:
// Player(int max) { maxHealth = max; } // שגיאה!
};האיברים מאותחלים בסדר שבו הם מוכרזים במחלקה, ולא בסדר שבו הם מופיעים ברשימת האתחול. כתוב תמיד את רשימת האתחול לפי סדר ההכרזה כדי למנוע בלבול.
אתגר
קלבואו נבנה מערכת תצורה למנוע משחק, המדגימה מתי ולמה רשימות אתחול של איברים חיוניות. תיצרו מחלקה GameConfig עם איברים שחייבים להיות מאותחלים באמצעות תחביר רשימת האתחול.
תיצרו שני קבצים כדי לארגן את הקוד שלכם:
GameConfig.h: הגדירו מחלקהGameConfigששומרת את הגדרות המשחק. המחלקה שלכם צריכה לכלול:const std::string gameName: שם המשחק, שאי אפשר לשנות לאחר היצירהconst int maxPlayers: מספר השחקנים המרבי, שנקבע בעת הבנייהint& difficultyRef: הפניה להגדרת קושי חיצוניתint screenWidthו-int screenHeight: איברים רגילים עבור הגדרות התצוגה- בנאי שמקבל את כל הפרמטרים הדרושים ומאתחל כל איבר באמצעות רשימת האתחול. רשימת האתחול צריכה להיות בסדר שבו האיברים מוצהרים במחלקה
- מתודה
display()שמדפיסה את התצורה בפורמט הזה:Game: <gameName> Max Players: <maxPlayers> Difficulty: <difficultyRef value> Resolution: <screenWidth>x<screenHeight>
main.cpp: קראו ערכי תצורה מהקלט וצרו אובייקט GameConfig. תצטרכו:- לקרוא מהקלט את שם המשחק (מחרוזת), מספר השחקנים המרבי (int), רמת הקושי (int), הרוחב (int) והגובה (int): כל ערך בשורה נפרדת
- ליצור משתנה מקומי מסוג
intעבור רמת הקושי, שאליו התצורה תפנה - ליצור אובייקט
GameConfigבאמצעות הבנאי עם רשימת האתחול - לקרוא ל-
display()כדי להציג את התצורה הראשונית - לשנות ישירות את משתנה רמת הקושי (להכפיל אותו ב-2)
- להדפיס
"After difficulty change:" - לקרוא שוב ל-
display()כדי להראות שההפניה משקפת את הערך המעודכן
האתגר הזה מדגיש למה רשימות אתחול חשובות: אי אפשר להציב ערכים באיברי const שלכם ובאיבר ההפניה בגוף הבנאי. חייבים לאתחל אותם ברשימה. איבר ההפניה גם מדגים כיצד שינויים במשתנה המקורי משתקפים דרך אובייקט התצורה.
כללו את קובץ הכותרת שלכם ב-main.cpp באמצעות #include "GameConfig.h".
נסו בעצמכם
#include <iostream>
#include <string>
#include "GameConfig.h"
using namespace std;
int main() {
// קראו את ערכי הקלט
string gameName;
getline(cin, gameName);
int maxPlayers;
cin >> maxPlayers;
int difficulty;
cin >> difficulty;
int width;
cin >> width;
int height;
cin >> height;
// TODO: צרו אובייקט GameConfig באמצעות הבנאי המשתמש ברשימת אתחול
// הבנאי צריך לקבל: gameName, maxPlayers, difficulty (בהעברה לפי הפניה), width, height
// TODO: קראו ל-display() כדי להציג את התצורה הראשונית
// TODO: שנו ישירות את המשתנה difficulty (הכפילו אותו ב-2)
// TODO: הדפיסו "After difficulty change:"
// TODO: קראו שוב ל-display() כדי להציג את התצורה המעודכנת
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 ותכונות טיפוסיםסיכום – מכל גנריתרגלו בעצמכם: קומפיילר C++ אונליין