مفهوم الـ Interface
جزء من قسم Object Oriented Programming في رحلة C على Coddy — الدرس 40 من 61.
حتى الآن، قامت الـ structs الخاصة بنا بمزج البيانات والسلوك معاً — اسم بجانب مؤشر دالة (function pointer)، على سبيل المثال. ولكن ماذا لو احتوى الـ struct على مؤشرات دوال فقط؟ هذا يخلق شيئاً قوياً: واجهة (interface).
تُعرّف الواجهة (interface) ما هي العمليات المتاحة دون تحديد كيفية عملها. إنها بمثابة عقد ينص على أن "أي كائن يقوم بتنفيذ هذه الواجهة يجب أن يوفر هذه الدوال".
typedef void (*LogFunc)(const char* message);
typedef struct {
LogFunc log;
} ILogger;لا يحتوي الـ ILogger struct على شيء سوى مؤشر دالة. ليس لديه بيانات خاصة به — فهو يصف السلوك فقط. وتعد البادئة "I" اصطلاحاً شائعاً يشير إلى أن هذه واجهة (interface).
أي كود يقبل ILogger لا يهتم بالمكان الذي تذهب إليه رسالة السجل. فقد يقوم بالطباعة على وحدة التحكم (console)، أو الكتابة في ملف، أو إرسال البيانات عبر الشبكة. المستدعي يعرف فقط أنه يمكنه استدعاء log:
void process(ILogger* logger, const char* msg) {
logger->log(msg); // لا نعرف كيف يقوم بعملية التسجيل
}هذا الفصل هو جوهر تعدد الأشكال. تعمل الدالة process مع أي تنفيذ للمسجل — يمكنك تبديل السلوكيات دون تغيير كود الدالة. في الدرس القادم، ستنشئ تنفيذات ملموسة تفي بعقد هذه الواجهة.
التحدي
سهللنقم ببناء واجهة ICalculator — وهي عبارة عن هيكل (struct) يحتوي فقط على مؤشرات دوال (function pointers)، مما يحدد العمليات التي يجب أن يدعمها أي حاسب دون تحديد كيفية عملها.
ستقوم بإنشاء ملفين لتنظيم الكود الخاص بك:
calculator.h: قم بتعريف الواجهة الخاصة بك هنا. أنشئ نوع مؤشر دالة يسمىBinaryOpيأخذ معلمين من نوعintويعيدint. ثم قم بتعريف هيكلICalculatorيحتوي فقط على مؤشري دوال:operate(من نوعBinaryOp) وdescribe(مؤشر دالة لا يأخذ أي معلمات ولا يعيد شيئاً). هذا الهيكل هو مجرد واجهة — فهو لا يحتوي على بيانات، بل سلوك فقط.main.c: قم بتضمين ملف الرأس (header) الخاص بك وقم بتنفيذ دوال ملموسة يمكنها تلبية الواجهة:add— يعيد مجموع عددين صحيحينmultiply— يعيد حاصل ضرب عددين صحيحينdescribe_add— يطبعAdditiondescribe_multiply— يطبعMultiplication
ICalculator، وقم بربطه بناءً على المدخلات، واستخدمه لإجراء عملية حسابية.
سيتلقى برنامجك ثلاثة مدخلات: عددان صحيحان و رمز العملية (1 للجمع، 2 للضرب).
بناءً على رمز العملية، قم بربط ICalculator الخاص بك بزوج الدوال المناسب. ثم استدعِ describe من خلال الواجهة لطباعة اسم العملية، متبوعاً باستدعاء operate لحساب النتيجة وطباعتها.
مثال على المخرجات عندما تكون المدخلات 5 و 3 و 1:
Addition
8مثال على المخرجات عندما تكون المدخلات 4 و 7 و 2:
Multiplication
28الفكرة الأساسية هي أن هيكل ICalculator الخاص بك يحدد عقداً — أي كود يستخدمه يعرف أنه يمكنه استدعاء describe و operate، دون معرفة الدوال المحددة التي تم ربطها. تذكر استخدام حراس التضمين (include guards) في ملف الرأس الخاص بك.
ورقة مرجعية
تُعد الواجهة (interface) هيكلاً (struct) يحتوي فقط على مؤشرات دوال، حيث تحدد ما هي العمليات المتاحة دون تحديد كيفية عملها.
تعريف الواجهة:
typedef void (*LogFunc)(const char* message);
typedef struct {
LogFunc log;
} ILogger;تُعد البادئة "I" عرفاً شائعاً يشير إلى أن هذا العنصر هو واجهة. لا يحتوي الهيكل على أي بيانات — فهو يصف السلوك فقط.
استخدام الواجهة:
void process(ILogger* logger, const char* msg) {
logger->log(msg); // لا نعرف كيف يتم التسجيل
}هذا الفصل يُمكّن من تحقيق تعدد الأشكال (polymorphism) — حيث تعمل الدالة مع أي تنفيذ للواجهة، مما يسمح لك بتبديل السلوكيات دون تغيير كود الدالة.
جرّب بنفسك
#include <stdio.h>
#include "calculator.h"
// TODO: تنفيذ دالة الجمع
// تعيد مجموع عددين صحيحين
// TODO: تنفيذ دالة الضرب
// تعيد ناتج ضرب عددين صحيحين
// TODO: تنفيذ دالة describe_add
// تطبع "Addition"
// TODO: تنفيذ دالة describe_multiply
// تطبع "Multiplication"
int main() {
int num1, num2, op_code;
scanf("%d", &num1);
scanf("%d", &num2);
scanf("%d", &op_code);
// TODO: إنشاء مثيل (instance) من ICalculator
// TODO: بناءً على op_code (1 للجمع، 2 للضرب)،
// قم بربط الآلة الحاسبة بالدوال المناسبة
// TODO: استدعاء describe من خلال الواجهة (interface)
// TODO: استدعاء operate من خلال الواجهة وطباعة النتيجة
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مشروع: رسّام الأشكال
نظرة عامة على المشروعتنفيذ الدائرة