نظرة عامة على المشروع
جزء من قسم Object Oriented Programming في رحلة C على Coddy — الدرس 44 من 61.
التحدي
سهلدعنا نضع الأساس لمشروع Shape Drawer من خلال إنشاء هيكل Shape الأساسي — وهو واجهة (interface) تحدد ما يمكن لأي شكل القيام به من خلال مؤشرات الدوال (function pointers).
ستقوم بإنشاء ملفين لإعداد هذا النظام متعدد الأشكال (polymorphic system):
shape.h: قم بتعريف الواجهة الأساسية هنا. أولاً، قم بإنشاء إعلان مسبق (forward declaration) لهيكلShape. ثم قم بتعريف نوعين من مؤشرات الدوال:DrawFunc— يأخذ معامل من نوعconst Shape*ولا يعيد شيئاًAreaFunc— يأخذ معامل من نوعconst Shape*ويعيدdouble
Shapeنفسه بحيث يحتوي على مؤشري دالة:draw(من نوعDrawFunc) وarea(من نوعAreaFunc). يعمل هذا الهيكل كواجهة بحتة — فهو لا يحتوي على بيانات خاصة بالشكل، بل يحتوي فقط على السلوك.main.c: أثبت أن واجهتك تعمل من خلال إنشاء شكل اختبار بسيط. قم بتنفيذ دالتين:test_draw— تطبعDrawing test shapetest_area— تعيد42.0
Shape، وقم بربطه بدوال الاختبار هذه، ثم استدعِ كلتيهما من خلال الواجهة. اطبع نتيجة المساحة بمنزلة عشرية واحدة.
يجب أن يوضح مخرجك أن مؤشرات الدوال تعمل بشكل صحيح:
Drawing test shape
Area: 42.0لماذا الإعلان المسبق؟ قد تتساءل لماذا يظهر typedef struct Shape Shape; قبل تعريف الهيكل بالكامل. هذا ضروري لأن DrawFunc و AreaFunc يشيران إلى const Shape* في أنواع المعاملات الخاصة بهما — ولكن في تلك النقطة من الملف، لم يكن المترجم (compiler) قد رأى تعريف الهيكل الكامل بعد. يخبر الإعلان المسبق المترجم: "يوجد هيكل باسم Shape"، وهو ما يكفي لاستخدام مؤشر إليه. يتبع ذلك التعريف الكامل لاحقاً. هذا النمط شائع في لغة C كلما احتاج الهيكل إلى الإشارة إلى نفسه (مباشرة أو من خلال مؤشرات الدوال).
الفكرة الأساسية هنا هي أن Shape لا يعرف أي شيء عن الدوائر أو المستطيلات — فهو يعرف فقط أن أي شكل يجب أن يكون قادراً على رسم نفسه (draw) وحساب مساحته (area). في الدروس القادمة، ستنشئ أشكالاً ملموسة تدمج هذا الهيكل الأساسي وتوفر تنفيذاتها الخاصة. تذكر استخدام حراس التضمين (include guards) في ملف الرأس (header file) الخاص بك.
جرّب بنفسك
#include <stdio.h>
#include "shape.h"
// TODO: تنفيذ دالة test_draw
// - تأخذ معامل من نوع const Shape*
// - تطبع "Drawing test shape"
void test_draw(const Shape* shape) {
// TODO: اطبع الرسالة المطلوبة
}
// TODO: تنفيذ دالة test_area
// - تأخذ معامل من نوع const Shape*
// - تعيد القيمة 42.0
double test_area(const Shape* shape) {
// TODO: أعد قيمة مساحة الاختبار
}
int main() {
// TODO: إنشاء مثيل (instance) من Shape
// TODO: ربط الـ shape بدالتي test_draw و test_area
// TODO: استدعاء draw من خلال الواجهة (interface)
// TODO: استدعاء area من خلال الواجهة وطباعتها بمنزلة عشرية واحدة
// التنسيق: "Area: %.1f\n"
return 0;
}
جميع دروس Object Oriented Programming
1أساسيات البرمجة التركيبية
ملفات الترويسةحواجز التضمينملفات المصدرالدوال الساكنةمراجعة: آلة حاسبة تركيبية4التغليف (Encapsulation)
مفهوم الـ Opaque Pointersتعريف الـ Opaque Structsالـ Getters والـ Settersالتحقق من البيانات في الـ Settersملخص: الصندوق السري2الكائنات والأساليب
الـ Structs ككائناتمؤشر 'Self'صحة استخدام Constالمؤشر مقابل القيمةالأساليب المساعدةملخص: Point Manager5مشروع: حساب بنكي بسيط
إعداد المشروعتنفيذ الحساب3دورة حياة الكائن
نمط المنشئ (Constructor Pattern)نمط الهادم (Destructor Pattern)تهيئة الـ Stackالنسخ العميق (Deep Copy)مراجعة: String Wrapper6الوراثة عبر التركيب
تضمين الـ Structقاعدة العضو الأولالوصول إلى أعضاء الأبعملية الـ Upcastingمراجعة: هرمية الأشكال9مشروع: رسّام الأشكال
نظرة عامة على المشروعتنفيذ الدائرة