מתודות ומשתנים סטטיים
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C++ של Coddy. שיעור 31 מתוך 104.
למדת שחברים סטטיים משותפים לכל האובייקטים. עכשיו נבחן איך להגדיר ולהשתמש כראוי במתודות סטטיות לצד משתנים סטטיים.
משתנים סטטיים שמוצהרים בתוך מחלקה חייבים להיות מוגדרים מחוץ למחלקה, בדרך כלל בקובץ מקור. הסיבה לכך היא שחברים סטטיים זקוקים למיקום אחסון יחיד בדיוק, המשותף לכל האובייקטים:
class Counter {
static int count; // הצהרה בלבד
public:
Counter() { count++; }
~Counter() { count--; }
static int getCount() { // מתודה סטטית
return count;
}
};
// הגדרה - נדרשת מחוץ למחלקה
int Counter::count = 0;מתודה סטטית שייכת למחלקה, ולא לאובייקט כלשהו. יש לכך השלכה חשובה: מתודות סטטיות לא יכולות לגשת לחברי מופע או להשתמש במצביע this, כי הן לא נקראות על אובייקט מסוים.
class MathUtils {
static double pi;
public:
static double circleArea(double radius) {
return pi * radius * radius; // אפשר לגשת לחברים סטטיים
}
};
double MathUtils::pi = 3.14159;
// נקראת ללא אובייקט
double area = MathUtils::circleArea(5.0);מתודות סטטיות אידיאליות לפונקציות שירות שאינן זקוקות למצב של אובייקט, למתודות מפעל שיוצרות אובייקטים או לגישה לנתונים סטטיים. מכיוון שהן אינן דורשות מופע של אובייקט, קוראים להן באמצעות שם המחלקה ואופרטור תחימת המרחב: ClassName::methodName().
אתגר
קלבוא נבנה מערכת ליצירת מזהים ייחודיים, שמדגימה כיצד מתודות ומשתנים סטטיים פועלים יחד כדי לספק פונקציונליות ברמת המחלקה בלי צורך במופעי אובייקטים.
תיצור שני קבצים כדי לארגן את הקוד שלך:
IDGenerator.h: הגדר מחלקהIDGeneratorשיוצרת מזהים ייחודיים עוקבים. למחלקה שלך צריכים להיות:- חבר סטטי פרטי
nextIdשעוקב אחר המזהה הבא שיש להקצות (מתחיל ב-1000) - חבר סטטי פרטי
prefix(מחרוזת) ששומר קידומת הניתנת להתאמה אישית לכל המזהים - מתודה סטטית
setPrefix(const std::string& p)שמשנה את הקידומת - מתודה סטטית
getNextId()שמחזירה מחרוזת המשלבת את הקידומת ואת מספר המזהה הנוכחי, ואז מגדילה אתnextIdעבור הקריאה הבאה - מתודה סטטית
peekNextId()שמחזירה מה יהיה המזהה הבא בלי להגדיל את המונה - מתודה סטטית
getGeneratedCount()שמחזירה כמה מזהים נוצרו (רמז: חשב לפי ערך ההתחלה והערך הנוכחי שלnextId) - מתודה סטטית
reset()שמחזירה אתnextIdל-1000
זכור להגדיר את החברים הסטטיים מחוץ למחלקה, אחרי הגדרת המחלקה. אתחל את
prefixל-"ID-".- חבר סטטי פרטי
main.cpp: הדגם קריאה למתודות סטטיות באמצעות שם המחלקה, בלי ליצור אובייקטים. קרא קידומת מותאמת אישית מהקלט, ואז:- הדפס
"Peek: <peeked_id>"באמצעותpeekNextId() - צור שלושה מזהים באמצעות
getNextId()והדפס כל אחד כך:"Generated: <id>" - הדפס
"Count: <count>"כדי להציג כמה מזהים נוצרו - שנה את הקידומת באמצעות ערך הקלט עם
setPrefix() - צור שני מזהים נוספים והדפס כל אחד כך:
"Generated: <id>" - הדפס שוב
"Count: <count>" - קרא ל-
reset() - הדפס
"After reset - Peek: <peeked_id>" - הדפס
"After reset - Count: <count>"
- הדפס
שים לב שאינך יוצר אף פעם אובייקט IDGenerator: כל המתודות נקראות ישירות במחלקה באמצעות IDGenerator::methodName(). זהו המאפיין המרכזי של מתודות סטטיות: הן שייכות למחלקה עצמה, ולא למופע מסוים כלשהו.
כלול את <string> ואת <iostream> בקובץ הכותרת שלך, ואל תשכח את שומרי הכותרת.
נסו בעצמכם
#include <iostream>
#include <string>
#include "IDGenerator.h"
using namespace std;
int main() {
// קרא קידומת מותאמת אישית מהקלט
string customPrefix;
cin >> customPrefix;
// TODO: הדפס "Peek: <peeked_id>" באמצעות peekNextId()
// TODO: צור שלושה מזהים באמצעות getNextId() והדפס כל אחד בתור "Generated: <id>"
// TODO: הדפס "Count: <count>" כדי להראות כמה מזהים נוצרו
// TODO: שנה את הקידומת לפי ערך הקלט באמצעות setPrefix()
// TODO: צור עוד שני מזהים והדפס כל אחד בתור "Generated: <id>"
// TODO: הדפס שוב "Count: <count>"
// TODO: קרא ל־reset()
// TODO: הדפס "After reset - Peek: <peeked_id>"
// TODO: הדפס "After reset - Count: <count>"
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++ אונליין