Menu
Coddy logo textTech

מצביעי פונקציות במבנים

חלק מהיחידה תכנות מונחה עצמים במסלול ה-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.

challenge icon

אתגר

קל

בואו נבנה מערכת Notifier שמדגימה כיצד מבנים יכולים לשאת את ההתנהגות שלהם באמצעות מצביעים לפונקציות.

תיצרו שני קבצים כדי לארגן את הקוד:

  • notifier.h: הגדירו סוג של מצביע לפונקציה בשם NotifyFunc שמקבל פרמטר const char* ואינו מחזיר ערך. לאחר מכן הגדירו מבנה Notifier שמכיל name (מסוג const char*) ומצביע לפונקציה בשם notify מסוג NotifyFunc.
  • main.c: כללו את קובץ הכותרת שלכם וממשו שתי פונקציות התראה:
    • alert_notify: מדפיסה את ההודעה בפורמט: [ALERT] message
    • info_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;
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר C אונליין