גטרים וסטרים
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C++ של Coddy. שיעור 28 מתוך 104.
כאשר חברי מחלקה הם פרטיים, קוד חיצוני אינו יכול לגשת אליהם ישירות. פונקציות גישה לקריאה ופונקציות גישה לעדכון הן מתודות ציבוריות שמאפשרות גישה מבוקרת לחברים הפרטיים האלה — פונקציות גישה לקריאה שולפות ערכים, ופונקציות גישה לעדכון משנות אותם.
class Temperature {
double celsius; // פרטי - אי אפשר לגשת אליו ישירות
public:
// פונקציית קריאה - מחזירה את הערך
double getCelsius() const {
return celsius;
}
// פונקציית עדכון - משנה את הערך לאחר בדיקת תקינות
void setCelsius(double value) {
if (value >= -273.15) { // בדיקה מול האפס המוחלט
celsius = value;
}
}
};הכוח האמיתי של פונקציות הגדרה הוא אימות.
במקום לאפשר להקצות כל ערך שהוא, אפשר לאכוף כללים. בדוגמה שלמעלה, טמפרטורות שמתחת לאפס המוחלט נדחות. ללא פונקציית הגדרה, כל אחד יכול להקצות נתונים לא תקינים ישירות.
גם getters יכולים לעבד נתונים לפני שהם מחזירים אותם:
class Temperature {
double celsius;
public:
double getCelsius() const { return celsius; }
// getter מחושב - אינו מאחסן fahrenheit, אלא מחשב אותו
double getFahrenheit() const {
return celsius * 9.0 / 5.0 + 32.0;
}
void setCelsius(double value) { celsius = value; }
};שימו לב למילת המפתח const ב-getters — היא מציינת שהם אינם משנים את האובייקט. Setters אינם יכולים להיות const, מכיוון שמטרתם היא לשנות ערכי איברים. דפוס זה של שימוש ב-getters וב-setters הוא יסודי לכימוס, ומעניק לכם שליטה מלאה על אופן הגישה לנתוני המחלקה שלכם ועל אופן השינוי שלהם.
אתגר
קלבואו נבנה מערכת פרופיל שחקן שמדגימה כיצד getters ו-setters מספקים גישה מבוקרת לנתונים פרטיים, כולל אימות ותכונות מחושבות.
תיצרו שני קבצים כדי לארגן את הקוד:
Player.h: הגדירו מחלקתPlayerשמנהלת את הפרופיל של דמות במשחק באמצעות גישה מוגנת לנתונים. המחלקה שלכם צריכה לכלול:- חברים פרטיים:
name(מחרוזת),level(int) ו-experience(int) - בנאי שמקבל שם ומאתחל את
levelל-1ואתexperienceל-0 - getter בשם
getName()שמחזירה את שם השחקן - getter בשם
getLevel()שמחזירה את הרמה הנוכחית - getter בשם
getExperience()שמחזירה את נקודות הניסיון הנוכחיות - setter בשם
setName()שמקבלת רק שמות באורך של לפחות 3 תווים; אם השם אינו תקין, השאירו את השם הנוכחי ללא שינוי - setter בשם
addExperience(int points)שמקבלת רק ערכים חיוביים. כשנקודות הניסיון מגיעות ל-100או עולות עליו, השחקן עולה רמה: הגדילו את הרמה ב-1 והפחיתו 100 מנקודות הניסיון. הדבר יכול להתרחש כמה פעמים אם מתווספות מספיק נקודות ניסיון. - getter מחושבת בשם
getExperienceToNextLevel()שמחזירה כמה נקודות ניסיון נוספות דרושות כדי להגיע לרמה הבאה (תמיד100 - current experience)
סמנו את כל ה-getters בתור
const, מכיוון שהם לא משנים את האובייקט.- חברים פרטיים:
main.cpp: הדגימו את פעולת ה-getters וה-setters שלכם. קראו מהקלט שם שחקן ונקודות ניסיון להוספה (כל אחד בשורה נפרדת), ואז:- צרו
Playerעם השם שהתקבל בקלט - הדפיסו
"Player: <name>, Level: <level>, XP: <experience>" - הוסיפו את נקודות הניסיון שהתקבלו בקלט באמצעות
addExperience() - הדפיסו שוב את אותה שורת מצב כדי להציג את המצב המעודכן
- הדפיסו
"XP to next level: <amount>" - נסו לשנות את השם ל-
"Al"(האימות אמור להיכשל) - הדפיסו
"Name after invalid change: <name>" - שנו את השם ל-
"Champion"(השינוי אמור להצליח) - הדפיסו
"Name after valid change: <name>"
- צרו
קלט נקודות הניסיון יסופק כמחרוזת שתצטרכו להמיר למספר שלם. כללו את קובץ הכותרת שלכם ב-main.cpp באמצעות #include "Player.h".
נסו בעצמכם
#include <iostream>
#include <string>
#include "Player.h"
using namespace std;
int main() {
// קרא את שם השחקן
string playerName;
getline(cin, playerName);
// קרא את נקודות הניסיון שיש להוסיף (כמחרוזת, המר ל-int)
string expString;
getline(cin, expString);
int expToAdd = stoi(expString);
// TODO: צור Player עם השם שהוזן
// TODO: הדפס את המצב ההתחלתי: "Player: <name>, Level: <level>, XP: <experience>"
// TODO: הוסף את נקודות הניסיון שהוזנו באמצעות addExperience()
// TODO: הדפס את שורת המצב המעודכנת
// TODO: הדפס "XP to next level: <amount>"
// TODO: נסה לשנות את השם ל-"Al" (האימות אמור להיכשל)
// TODO: הדפס "Name after invalid change: <name>"
// TODO: שנה את השם ל-"Champion" (השינוי אמור להצליח)
// TODO: הדפס "Name after valid change: <name>"
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++ אונליין