محاكاة الـ Methods
جزء من قسم البرمجة كائنية التوجه في رحلة C على Coddy. الدرس 39 من 61.
لقد رأيت كيف تضع مؤشر دالة داخل بنية. تظهر القوة الحقيقية عندما تُسنِد دوالًا مختلفة إلى مثيلات مختلفة من نوع البنية نفسه. بهذه الطريقة نحاكي الأساليب ذات السلوك المتنوع.
تأمّل بنيةً تمثّل إجراءً بمنطق قابل للتخصيص:
typedef void (*ActionFunc)(void);
typedef struct {
const char* name;
ActionFunc execute;
} Action;عند إنشاء النسخ، اربط كل نسخة بدالة مختلفة:
void say_hello(void) {
printf("Hello!\n");
}
void say_goodbye(void) {
printf("Goodbye!\n");
}
int main() {
Action greet = { "Greet", say_hello };
Action farewell = { "Farewell", say_goodbye };
greet.execute(); // المخرجات: Hello!
farewell.execute(); // المخرجات: Goodbye!
return 0;
}كلٌّ من greet وfarewell من النوع نفسه (Action)، ومع ذلك فإن استدعاء execute على كلٍّ منهما يؤدي إلى نتائج مختلفة تمامًا. لا تحتفظ البنية بالبيانات فحسب، بل تحتفظ أيضًا بسلوك يختلف باختلاف المثيل.
يعكس هذا النمط طريقة عمل الكائنات في لغات البرمجة الأخرى: إذ يمكن لكل كائن أن يمتلك تنفيذه الخاص لإحدى الطرق، رغم اشتراكها في الواجهة نفسها.
التحدي
سهللنبنِ نظام Speaker يوضّح كيف يمكن لنسخ مختلفة من النوع نفسه للبنية أن تُظهر سلوكيات مختلفة تمامًا، بناءً على الدالة الموصولة بها.
ستنشئ ملفين لتنظيم التعليمات البرمجية:
speaker.h: عرّف نوع مؤشر دالة باسمSpeakFuncلا يأخذ أي معاملات ولا يعيد أي قيمة. ثم عرّف بنيةSpeakerتحتوي علىname(وهوconst char*) ومؤشر دالةspeakمن النوعSpeakFunc.main.c: أدرج ملف الترويسة ونفّذ ثلاث دوال مختلفة لإصدار الأصوات:bark: تطبعWoof!meow: تطبعMeow!chirp: تطبعChirp!
Speaker، وصِل كلًّا منهما بدالة مختلفة بناءً على الإدخال، واستدعِ طريقتيspeakفيهما لرؤية تعدد الأشكال أثناء العمل.
سيستقبل برنامجك مدخلين: نوع المتحدث الأول (1 لـ bark، و2 لـ meow، و3 لـ chirp) ونوع المتحدث الثاني (أيضًا 1 أو 2 أو 3).
أنشئ نسختين من Speaker. يمكنك تسميتهما كما تشاء (مثل "Dog" أو "Cat" أو "Bird"، أو ببساطة "Speaker1" و"Speaker2"). صِل كل نسخة بالدالة المناسبة وفقًا لرمز الإدخال الخاص بها، ثم استدعِ speak لكل نسخة بالترتيب.
مثال على المخرجات عندما يكون النوع الأول 1 والنوع الثاني 2:
Woof!
Meow!مثال على المخرجات عندما يكون النوع الأول 3 والنوع الثاني 3:
Chirp!
Chirp!الفكرة الأساسية هنا هي أن كلا المتحدثين من النوع نفسه Speaker، ومع ذلك ينتجان مخرجات مختلفة لأن لكل منهما دالة مختلفة معيّنة لعضو speak. تذكّر استخدام حواجز التضمين في ملف الترويسة.
جرّب بنفسك
#include <stdio.h>
#include "speaker.h"
// TODO: نفّذ الدالة bark التي تطبع "Woof!"
// TODO: نفّذ الدالة meow التي تطبع "Meow!"
// TODO: نفّذ الدالة chirp التي تطبع "Chirp!"
int main() {
int type1, type2;
scanf("%d", &type1);
scanf("%d", &type2);
// TODO: أنشئ مثيلين من Speaker
// TODO: اربط الدالة speak للمتحدث الأول بناءً على type1
// (1 = bark، 2 = meow، 3 = chirp)
// TODO: اربط الدالة speak للمتحدث الثاني بناءً على type2
// (1 = bark، 2 = meow، 3 = chirp)
// TODO: استدعِ speak لكل متحدث بالترتيب
return 0;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
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مشروع: رسّام الأشكال
نظرة عامة على المشروعتنفيذ الدائرةتنفيذ المستطيلاستخدام تعدد الأشكالحاوية الأشكالتدرّب بنفسك: مترجم C عبر الإنترنت