مؤشرات الدوال في الـ Structs
جزء من قسم Object Oriented Programming في رحلة C على Coddy — الدرس 38 من 61.
حتى الآن، استخدمنا مؤشرات الدوال كمتغيرات مستقلة أو مررناها كوسطاء. الخطوة التالية نحو تعدد الأشكال (polymorphism) هي تضمين مؤشر دالة مباشرة داخل struct — مما يمنح الـ struct سلوكاً خاصاً به.
عندما يحتوي الـ struct على مؤشر دالة (function pointer)، يمكن لكل مثيل (instance) أن يحمل دالة مختلفة. وهذا يعني أن كائنين من نفس النوع يمكن أن يتصرفا بشكل مختلف عند استدعاء مؤشر الدالة الخاص بهما:
typedef void (*PrintFunc)(const char*);
typedef struct {
const char* name;
PrintFunc print; // مؤشر دالة كعضو
} Printer;يحتوي الـ Printer struct الآن على عضوين: بيانات (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 — حيث يمكن تعيين دوال مختلفة لمثيلات (instances) مختلفة، مما ينتج عنه سلوكيات مختلفة من نفس نوع الـ struct.
التحدي
سهللنقم ببناء نظام Notifier يوضح كيف يمكن للهياكل (structs) أن تحمل سلوكها الخاص من خلال مؤشرات الدوال (function pointers).
ستقوم بإنشاء ملفين لتنظيم الكود الخاص بك:
notifier.h: قم بتعريف نوع مؤشر دالة يسمىNotifyFuncيأخذ معامل من نوعconst char*ولا يعيد شيئاً. ثم قم بتعريف هيكلNotifierيحتوي علىname(من نوعconst char*) ومؤشر دالةnotifyمن النوعNotifyFunc.main.c: قم بتضمين ملف الرأس الخاص بك وتنفيذ دالتي إشعار:alert_notify— تطبع الرسالة بالتنسيق التالي:[ALERT] messageinfo_notify— تطبع الرسالة بالتنسيق التالي:[INFO] message
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)
جرّب بنفسك
#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;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات البرمجة التركيبية
ملفات الترويسةحواجز التضمينملفات المصدرالدوال الساكنةمراجعة: آلة حاسبة تركيبية4التغليف (Encapsulation)
مفهوم الـ Opaque Pointersتعريف الـ Opaque Structsالـ Getters والـ Settersالتحقق من البيانات في الـ Settersملخص: الصندوق السري2الكائنات والأساليب
الـ Structs ككائناتمؤشر 'Self'صحة استخدام Constالمؤشر مقابل القيمةالأساليب المساعدةملخص: Point Manager5مشروع: حساب بنكي بسيط
إعداد المشروعتنفيذ الحساب8تعدد الأشكال (Polymorphism)
مؤشرات الدوال في الـ Structsمحاكاة الـ Methodsمفهوم الـ Interfaceتنفيذ الـ Interfacesالتكرار متعدد الأشكالمراجعة: Greeter3دورة حياة الكائن
نمط المنشئ (Constructor Pattern)نمط الهادم (Destructor Pattern)تهيئة الـ Stackالنسخ العميق (Deep Copy)مراجعة: String Wrapper6الوراثة عبر التركيب
تضمين الـ Structقاعدة العضو الأولالوصول إلى أعضاء الأبعملية الـ Upcastingمراجعة: هرمية الأشكال9مشروع: رسّام الأشكال
نظرة عامة على المشروعتنفيذ الدائرةتنفيذ المستطيلاستخدام تعدد الأشكالحاوية الأشكال