استدعاء مؤشرات الدوال
جزء من قسم Object Oriented Programming في رحلة C على Coddy — الدرس 34 من 61.
الآن بعد أن عرفت كيفية التصريح عن مؤشر دالة وتعيين دالة له، فإن الخطوة التالية هي استدعاء الدالة فعلياً من خلال ذلك المؤشر.
الصيغة بسيطة ومباشرة — يمكنك استخدام مؤشر الدالة (function pointer) تماماً كما تستدعي دالة عادية:
int add(int a, int b) {
return a + b;
}
int main() {
int (*operation)(int, int) = add;
int result = operation(5, 3); // يستدعي add(5, 3)
printf("%d\n", result); // المخرجات: 8
return 0;
}ببساطة، اكتب اسم المؤشر متبوعاً بأقواس تحتوي على الوسائط. تقوم لغة C تلقائياً بإلغاء إسناد المؤشر وتنفيذ الدالة التي يشير إليها.
يمكنك أيضًا استخدام صيغة إلغاء المرجع الصريحة مع (*operation)(5, 3)، لكنها اختيارية وأقل شيوعًا. كلا الشكلين ينتجان نتائج متطابقة.
تظهر القوة الحقيقية عندما تعيد تعيين المؤشر إلى دوال مختلفة:
int subtract(int a, int b) {
return a - b;
}
operation = subtract;
result = operation(5, 3); // يستدعي الآن subtract(5, 3)
printf("%d\n", result); // المخرجات: 2نفس المتغير operation ينفذ الآن منطقاً مختلفاً تماماً. هذه القدرة على تبديل السلوك في وقت التشغيل هي أساس تعدد الأشكال (polymorphism) في لغة C.
التحدي
سهلدعونا نتدرب على استدعاء الدوال من خلال المؤشرات (pointers) وتبديل الدالة التي يتم تنفيذها. ستقوم ببناء آلة حاسبة بسيطة يمكنها التبديل بين الجمع والطرح أثناء وقت التشغيل.
اكتب برنامجاً يقوم بما يلي:
- تعريف دالتين:
add— تأخذ معاملين من نوعintوتعيد مجموعهماsubtract— تأخذ معاملين من نوعintوتعيد ناتج طرح الثاني من الأول
- في الدالة
main، قم بالتصريح عن مؤشر دالة يسمىcalcيمكنه الإشارة إلى دوال تأخذ معاملين من نوعintوتعيد قيمة من نوعint - قراءة أربعة مدخلات: عددين صحيحين ورمزين للعمليات
- لكل رمز عملية:
- تعيين الدالة المناسبة للمؤشر
calc(1 للجمعadd، و 2 للطرحsubtract) - استدعاء الدالة من خلال المؤشر مع العددين
- طباعة النتيجة
- تعيين الدالة المناسبة للمؤشر
ستتلقى أربعة مدخلات: العدد الأول، العدد الثاني، رمز العملية الأول (1 أو 2)، و رمز العملية الثاني (1 أو 2).
يجب أن يظهر مخرجك نتيجتين في سطرين منفصلين — نتيجة لكل عملية تم إجراؤها باستخدام نفس العددين:
15
5في هذا المثال، مع المدخلات 10، 5، 1، 2: العملية الأولى (الرمز 1) تجمع 10 + 5 = 15، ثم يتم إعادة تعيين المؤشر، والعملية الثانية (الرمز 2) تطرح 10 - 5 = 5.
يوضح هذا كيف يمكن لمتغير المؤشر نفسه تنفيذ منطق مختلف تماماً عن طريق إعادة تعيينه بين الاستدعاءات.
ورقة مرجعية
لاستدعاء دالة من خلال مؤشر، استخدم اسم المؤشر متبوعاً بأقواس تحتوي على الوسائط:
int add(int a, int b) {
return a + b;
}
int main() {
int (*operation)(int, int) = add;
int result = operation(5, 3); // يستدعي add(5, 3)
printf("%d\n", result); // المخرج: 8
return 0;
}يمكنك أيضاً استخدام صيغة إلغاء المرجعية الصريحة (*operation)(5, 3)، لكنها اختيارية.
يمكن إعادة تعيين مؤشرات الدوال للإشارة إلى دوال مختلفة أثناء وقت التشغيل:
int subtract(int a, int b) {
return a - b;
}
operation = subtract;
result = operation(5, 3); // يستدعي الآن subtract(5, 3)
printf("%d\n", result); // المخرج: 2يسمح هذا لمتغير المؤشر نفسه بتنفيذ منطق مختلف عن طريق إعادة تعيينه بين الاستدعاءات.
جرّب بنفسك
#include <stdio.h>
// TODO: قم بتعريف دالة الجمع (add) هنا
// TODO: قم بتعريف دالة الطرح (subtract) هنا
int main() {
// قراءة المدخلات
int num1, num2, op1, op2;
scanf("%d", &num1);
scanf("%d", &num2);
scanf("%d", &op1);
scanf("%d", &op2);
// TODO: قم بالتصريح عن مؤشر دالة يسمى 'calc' يمكنه الإشارة إلى
// دوال تأخذ معاملين من نوع int وتعيد قيمة من نوع int
// TODO: بالنسبة لرمز العملية الأول (op1):
// - قم بتعيين الدالة المناسبة لـ calc (1 للجمع، 2 للطرح)
// - استدعِ الدالة من خلال المؤشر واطبع النتيجة
// TODO: بالنسبة لرمز العملية الثاني (op2):
// - أعد تعيين calc للدالة المناسبة
// - استدعِ الدالة من خلال المؤشر واطبع النتيجة
return 0;
}يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات البرمجة التركيبية
ملفات الترويسةحواجز التضمينملفات المصدرالدوال الساكنةمراجعة: آلة حاسبة تركيبية4التغليف (Encapsulation)
مفهوم الـ Opaque Pointersتعريف الـ Opaque Structsالـ Getters والـ Settersالتحقق من البيانات في الـ Settersملخص: الصندوق السري7مؤشرات الدوال
التصريح عن مؤشرات الدوالاستدعاء مؤشرات الدوالاستخدام Typedef لمؤشرات الدوالتمرير الدوال كوسطاءمراجعة: Calculator Dispatch2الكائنات والأساليب
الـ Structs ككائناتمؤشر 'Self'صحة استخدام Constالمؤشر مقابل القيمةالأساليب المساعدةملخص: Point Manager5مشروع: حساب بنكي بسيط
إعداد المشروعتنفيذ الحساب3دورة حياة الكائن
نمط المنشئ (Constructor Pattern)نمط الهادم (Destructor Pattern)تهيئة الـ Stackالنسخ العميق (Deep Copy)مراجعة: String Wrapper6الوراثة عبر التركيب
تضمين الـ Structقاعدة العضو الأولالوصول إلى أعضاء الأبعملية الـ Upcastingمراجعة: هرمية الأشكال9مشروع: رسّام الأشكال
نظرة عامة على المشروعتنفيذ الدائرة