מצביעי פונקציות במבנים
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C של Coddy. שיעור 38 מתוך 61.
עד עכשיו השתמשנו במצביעי פונקציות כמשתנים עצמאיים או העברנו אותם כארגומנטים. הצעד הבא לקראת פולימורפיזם הוא הטמעת מצביע פונקציה ישירות בתוך struct, וכך להקנות ל-struct התנהגות משלו.
כאשר מבנה מכיל מצביע לפונקציה, כל מופע יכול להכיל פונקציה אחרת. פירוש הדבר הוא ששני אובייקטים מאותו סוג יכולים להתנהג אחרת כשקוראים למצביע הפונקציה שלהם:
typedef void (*PrintFunc)(const char*);
typedef struct {
const char* name;
PrintFunc print; // מצביע לפונקציה כשדה במבנה
} Printer;למבנה Printer יש עכשיו שני איברים: נתונים (name) והתנהגות (print). כדי להשתמש בו, משייכים פונקציה למצביע במהלך האתחול:
void loud_print(const char* msg) {
printf("!!! %s !!!\n", msg);
}
int main() {
Printer p;
p.name = "Alert";
p.print = loud_print;
p.print("Hello"); // פלט: !!! Hello !!!
return 0;
}שימו לב איך אנחנו קוראים לפונקציה דרך המבנה: p.print("Hello"). הדבר דומה מאוד לקריאה למתודה על אובייקט בשפות אחרות. המבנה מכיל גם את הנתונים שלו וגם את הפונקציה שפועלת עליו.
תבנית זו היא הבסיס לפולימורפיזם ב-C: למופעים שונים אפשר להקצות פונקציות שונות, וכך ליצור התנהגויות שונות מאותו סוג struct.
אתגר
קלבואו נבנה מערכת Notifier שמדגימה כיצד מבנים יכולים לשאת את ההתנהגות שלהם באמצעות מצביעים לפונקציות.
תיצרו שני קבצים כדי לארגן את הקוד:
notifier.h: הגדירו סוג של מצביע לפונקציה בשםNotifyFuncשמקבל פרמטרconst char*ואינו מחזיר ערך. לאחר מכן הגדירו מבנהNotifierשמכילname(מסוגconst char*) ומצביע לפונקציה בשםnotifyמסוגNotifyFunc.main.c: כללו את קובץ הכותרת שלכם וממשו שתי פונקציות התראה:alert_notify: מדפיסה את ההודעה בפורמט:[ALERT] messageinfo_notify: מדפיסה את ההודעה בפורמט:[INFO] message
Notifier, שייכו אליו את הפונקציה המתאימה בהתאם לקלט, וקראו לפונקציית ההתראה דרך מצביע הפונקציה שבמבנה.
התוכנית שלכם תקבל שני קלטים: סוג התראה (1 להתראה, 2 למידע) והודעה להצגה.
בהתאם לסוג, שייכו את הפונקציה המתאימה לחבר notify של ה-notifier שלכם, ואז קראו לה דרך המבנה כדי להציג את ההודעה.
פלט לדוגמה כאשר הסוג הוא 1 וההודעה היא "System starting":
[ALERT] System startingפלט לדוגמה כאשר הסוג הוא 2 וההודעה היא "All systems normal":
[INFO] All systems normalזכרו להשתמש בשומרי הכללה בקובץ הכותרת שלכם, ולקרוא לפונקציה דרך חבר המבנה: n.notify(message)
נסו בעצמכם
#include <stdio.h>
#include "notifier.h"
// TODO: לממש את הפונקציה alert_notify
// יש להדפיס: [ALERT] message
// TODO: לממש את הפונקציה info_notify
// יש להדפיס: [INFO] message
int main() {
int type;
char message[256];
// לקרוא את הקלט
scanf("%d", &type);
getchar(); // לצרוך את תו השורה החדשה
fgets(message, sizeof(message), stdin);
// להסיר את תו השורה החדשה בסוף message, אם קיים
int len = 0;
while (message[len] != '\0') len++;
if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
// TODO: ליצור מופע של Notifier
// TODO: בהתאם ל-type (1 עבור alert, 2 עבור info),
// להקצות את הפונקציה המתאימה לשדה notify של notifier
// TODO: להפעיל את ההתראה באמצעות מצביע הפונקציה של המבנה
// יש להשתמש ב־n.notify(message)
return 0;
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
4כימוס
המושג של מצביעים אטומיםהגדרת מבנים אטומיםפונקציות Get ו-Setאימות ב-Settersסיכום: הקופסה הסודית2אובייקטים ומתודות
מבנים כאובייקטיםמצביע 'Self'נכונות constמצביע לעומת ערךמתודות עזרחזרה: מנהל נקודות5פרויקט: חשבון בנק פשוט
הגדרת הפרויקטמימוש החשבוןתרגלו בעצמכם: קומפיילר C אונליין