محاكاة الـ Methods
جزء من قسم البرمجة كائنية التوجه في رحلة C على Coddy. الدرس 39 من 61.
لقد رأيت كيف تضع مؤشّر function داخل بنية. تظهر القوة الحقيقية عندما تعيّن دوالًا مختلفة إلى instances مختلفة من نوع البنية نفسه. هكذا نحاكي methods ذات سلوك متباين.
تأمل بنيةً تمثّل إجراءً بمنطق قابل للتخصيص:
typedef void (*ActionFunc)(void);
typedef struct {
const char* name;
ActionFunc execute;
} Action;عند إنشاء instances، تقوم بربط functions مختلفة بكل واحدة منها:
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 عبر الإنترنت