העמסת האופרטורים [] ו־()
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C++ של Coddy. שיעור 45 מתוך 104.
אופרטור האינדקס ([]) מאפשר למחלקה שלך להתנהג כמו מערך, ומספק גישה לאלמנטים לפי אינדקס. אופרטור הקריאה לפונקציה (()) הופך אובייקטים לישויות שניתן לקרוא להן, המכונות פונקטורים.
הנה מעטפת פשוטה למערך עם אופרטור האינדקס:
class IntArray {
int* data;
size_t size;
public:
IntArray(size_t s) : size(s), data(new int[s]()) {}
~IntArray() { delete[] data; }
int& operator[](size_t index) {
return data[index];
}
const int& operator[](size_t index) const {
return data[index];
}
};שימו לב שאנחנו מספקים שתי גרסאות: אחת מחזירה הפניה שאינה const (ומאפשרת שינוי), והגרסה const פועלת עם אובייקטים מסוג const. כך אפשר לכתוב arr[0] = 5; לצורך קריאה וכתיבה.
אופרטור הקריאה לפונקציה יוצר אובייקטים שאפשר "לקרוא" להם כמו לפונקציות:
class Multiplier {
int factor;
public:
Multiplier(int f) : factor(f) {}
int operator()(int value) const {
return value * factor;
}
};
Multiplier triple(3);
int result = triple(10); // מחזיר 30פונקטורים הם רבי־עוצמה כי הם יכולים לשמור על מצב בין קריאות, בניגוד לפונקציות רגילות. משתמשים בהם לעיתים קרובות עם אלגוריתמים של STL, כשנדרשת התנהגות שניתן להתאים אישית ושזוכרת ערכי תצורה.
אתגר
קלבואו נבנה מחלקה ScoreTracker שמשלבת גם את אופרטור האינדקס וגם את אופרטור הקריאה לפונקציה. המחלקה הזאת תאחסן ציונים של שחקנים ותאפשר לך לגשת אליהם לפי אינדקס באמצעות [], ובו בזמן תפעל כפונקטור שמחיל מכפיל בונוס על כל ציון שתעביר לו.
תיצור שני קבצים כדי לארגן את הקוד שלך:
ScoreTracker.h: הגדר מחלקהScoreTrackerשמנהלת מערך של ציוני שחקנים ויכולה להחיל בונוסים. המחלקה שלך צריכה לכלול:- מערך
int*שהוקצה באופן דינמי כדי לאחסן ציונים - איבר
size_tלמספר הציונים - איבר
doubleלמכפיל הבונוס - בנאי שמקבל את הגודל ואת מכפיל הבונוס, ומאתחל את כל הציונים ל-0
- הורס שמנקה כראוי את הזיכרון הדינמי
- את אופרטור האינדקס
[](גם גרסה const וגם גרסה שאינה const) כדי לגשת לציונים לפי אינדקס - את אופרטור הקריאה לפונקציה
(), שמקבל ציון מסוגintומחזיר את הציון כשהוא מוכפל במכפיל הבונוס (בתורint) - מתודה
getSize()שמחזירה את מספר הציונים
אופרטור האינדקס שאינו const מחזיר הפניה, כך שאפשר לכתוב
tracker[0] = 100;. הגרסה const מאפשרת גישה לקריאה בלבד עבור אובייקטים מסוג const. יש לסמן את אופרטור הקריאה לפונקציה כ-const, מכיוון שהוא אינו משנה את מצב האובייקט.- מערך
main.cpp: קרא את הקלטים הבאים (כל אחד בשורה נפרדת):- מספר השחקנים (גודל)
- מכפיל הבונוס (בתור double)
- הציונים של כל שחקן (אחד בכל שורה, כמספר השחקנים)
- ציון לבדיקה שעליו יש להחיל את הבונוס
צור
ScoreTracker, השתמש באופרטור האינדקס כדי לאחסן את הציון של כל שחקן, ואז הצג את כל הציונים. לבסוף, השתמש באופרטור הקריאה לפונקציה כדי לחשב את הציון לאחר החלת הבונוס.תבנית הפלט:
Player 0: <score> Player 1: <score> ... Bonus applied to <test_score>: <result>
לדוגמה, עבור 3 שחקנים, מכפיל של 1.5, ציונים 100, 200, 150 וציון לבדיקה 80:
Player 0: 100
Player 1: 200
Player 2: 150
Bonus applied to 80: 120השתמש ב-std::stoi() וב-std::stod() להמרת הקלט. אל תשכח להוסיף guards לכותרת בקובץ הכותרת שלך.
נסו בעצמכם
#include <iostream>
#include <string>
#include "ScoreTracker.h"
using namespace std;
// TODO: לממש את הבנאי של ScoreTracker
ScoreTracker::ScoreTracker(size_t size, double multiplier) {
// TODO: לאתחל את המשתנים החברים ולהקצות מערך דינמי
// לאתחל את כל הניקודים ל-0
}
// TODO: לממש את ההורס של ScoreTracker
ScoreTracker::~ScoreTracker() {
// TODO: לשחרר את הזיכרון הדינמי
}
// TODO: לממש את אופרטור הגישה לפי אינדקס שאינו const
// TODO: לממש את אופרטור הגישה לפי אינדקס שהוא const
// TODO: לממש את אופרטור הקריאה לפונקציה
// TODO: לממש את המתודה getSize
size_t ScoreTracker::getSize() const {
// TODO: להחזיר את מספר הניקודים
}
int main() {
string line;
// לקרוא את מספר השחקנים
getline(cin, line);
size_t numPlayers = stoi(line);
// לקרוא את מכפיל הבונוס
getline(cin, line);
double multiplier = stod(line);
// TODO: ליצור ScoreTracker עם numPlayers ו-multiplier
// TODO: לקרוא את הניקוד של כל שחקן ולשמור אותו באמצעות אופרטור האינדקס
// TODO: לקרוא את ניקוד הבדיקה
// TODO: להציג את הניקוד של כל השחקנים בפורמט: "Player X: <score>"
// TODO: להציג את התוצאה לאחר החלת הבונוס בפורמט: "Bonus applied to <test_score>: <result>"
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++ אונליין