Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

مؤشرات الدوال في الـ Structs

جزء من قسم البرمجة كائنية التوجه في رحلة C على Coddy. الدرس 38 من 61.

حتى الآن، استخدمنا مؤشرات الدوال كمتغيرات مستقلة أو مررناها كوسائط. والخطوة التالية نحو تعدد الأشكال هي تضمين مؤشر دالة مباشرةً داخل بنية، مما يمنح البنية سلوكها الخاص.

عندما تحتوي بنية على مؤشر function، يمكن لكل instance الاحتفاظ بـ function مختلفة. وهذا يعني أن كائنين من النوع نفسه يمكن أن يتصرفا بشكل مختلف عند استدعاء function pointer الخاص بهما:

typedef void (*PrintFunc)(const char*);

typedef struct {
    const char* name;
    PrintFunc print;  // مؤشر دالة كعضو
} Printer;

تحتوي بنية Printer الآن على عضوين: البيانات (name) والسلوك (print). لاستخدامها، عليك تنفيذ assign دالة إلى المؤشر أثناء التهيئة:

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: يمكن أن تكون لدى الحالات المختلفة دوال مختلفة مُعيَّنة، مما ينتج سلوكيات مختلفة من نوع البنية نفسه.

challenge icon

التحدي

سهل

لنبنِ نظام Notifier يوضّح كيف يمكن للـ structs حمل سلوكها الخاص من خلال مؤشرات الدوال.

ستنشئ ملفين لتنظيم التعليمات البرمجية:

  • notifier.h: عرّف نوع مؤشر دالة يُسمّى NotifyFunc، ويأخذ معامل const char* ولا يُرجع شيئًا. ثم عرّف struct من نوع Notifier يحتوي على name (من النوع const char*) ومؤشر دالة notify من النوع NotifyFunc.
  • main.c: أدرج ملف الترويسة الخاص بك ونفّذ دالتي notification:
    • alert_notify: تطبع message بالتنسيق: [ALERT] message
    • info_notify: تطبع message بالتنسيق: [INFO] message
    ثم أنشئ instance من Notifier، واربط function المناسبة استنادًا إلى input، واستدعِ notification من خلال مؤشر function الخاص بالـ struct.

سيستقبل برنامجك inputين: نوع notification (1 للتنبيه، و2 للمعلومات) وmessage لعرضها.

استنادًا إلى النوع، عيّن function المطابقة إلى member notify الخاص بـ notifier، ثم استدعها من خلال الـ struct لعرض message.

مثال على المخرجات عندما يكون النوع 1 وmessage هو "System starting":

[ALERT] System starting

مثال على المخرجات عندما يكون النوع 2 وmessage هو "All systems normal":

[INFO] All systems normal

تذكّر استخدام include guards في ملف الترويسة، واستدعاء function من خلال member الخاص بالـ struct: 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 للتنبيه، 2 للمعلومات)،
    // عيّن الدالة المناسبة لعضو notify في الـ notifier
    
    
    // TODO: استدعِ الإشعار عبر مؤشر الدالة في الـ struct
    // استخدم: n.notify(message)
    
    
    return 0;
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم C عبر الإنترنت