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

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

جزء من قسم Object Oriented Programming في رحلة C على Coddy — الدرس 38 من 61.

حتى الآن، استخدمنا مؤشرات الدوال كمتغيرات مستقلة أو مررناها كوسائط. الخطوة التالية نحو تعدد الأشكال (polymorphism) هي تضمين مؤشر دالة مباشرة داخل هيكل (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;
}

لاحظ كيف نستدعي الدالة من خلال الـ struct: p.print("Hello"). يبدو هذا مشابهاً بشكل ملحوظ لاستدعاء method على كائن في لغات أخرى. يحمل الـ struct كلاً من بياناته والدالة التي تعمل عليها.

هذا النمط هو أساس تعدد الأشكال (polymorphism) في لغة C — حيث يمكن تخصيص دوال (functions) مختلفة لمثيلات (instances) مختلفة، مما ينتج سلوكيات مختلفة من نفس نوع الـ struct.

challenge icon

التحدي

سهل

لنقم ببناء نظام Notifier يوضح كيف يمكن للهياكل (structs) أن تحمل سلوكها الخاص من خلال مؤشرات الدوال (function pointers).

ستقوم بإنشاء ملفين لتنظيم الكود الخاص بك:

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

سيتلقى برنامجك مدخلين: نوع الإشعار (1 للتنبيه "alert"، و 2 للمعلومات "info") و رسالة لعرضها.

بناءً على النوع، قم بتعيين الدالة المقابلة لعضو notify في الـ notifier الخاص بك، ثم استدعها من خلال الهيكل لعرض الرسالة.

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

[ALERT] System starting

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

[INFO] All systems normal

تذكر استخدام حراس التضمين (include guards) في ملف الرأس الخاص بك، واستدعاء الدالة من خلال عضو الهيكل: n.notify(message)

ورقة مرجعية

يمكن تضمين مؤشرات الدوال مباشرة داخل الهياكل (structs)، مما يمنح كل مثيل (instance) سلوكه الخاص. هذا هو الأساس لتعدد الأشكال (polymorphism) في لغة C.

تعريف هيكل (Struct) بمؤشر دالة

أولاً، قم بتعريف نوع مؤشر دالة، ثم قم بتضمينه كعضو في الهيكل:

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

typedef struct {
    const char* name;
    PrintFunc print;  // Function pointer as a member
} Printer;

استخدام الهيكل

قم بتعيين دالة للمؤشر أثناء التهيئة، ثم استدعها من خلال الهيكل:

void loud_print(const char* msg) {
    printf("!!! %s !!!\n", msg);
}

int main() {
    Printer p;
    p.name = "Alert";
    p.print = loud_print;
    
    p.print("Hello");  // Output: !!! Hello !!!
    return 0;
}

الصيغة p.print("Hello") تستدعي الدالة من خلال الهيكل، بشكل مشابه لاستدعاء تابع (method) على كائن (object) في لغات أخرى.

سلوك تعدد الأشكال (Polymorphic Behavior)

يمكن أن يكون لمثيلات مختلفة من نفس نوع الهيكل دوال مختلفة معينة لها، مما ينتج سلوكيات مختلفة من نفس نوع الهيكل.

جرّب بنفسك

#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: إنشاء مثيل (instance) من Notifier
    
    
    // TODO: بناءً على type (1 للتنبيه، 2 للمعلومات)،
    // تعيين الدالة المناسبة للعضو notify الخاص بـ notifier
    
    
    // TODO: استدعاء الإشعار من خلال مؤشر الدالة (function pointer) الخاص بـ struct
    // استخدم: n.notify(message)
    
    
    return 0;
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming