تعريف الـ Opaque Structs
جزء من قسم البرمجة كائنية التوجه في رحلة C على Coddy. الدرس 18 من 61.
بعد أن فهمت مفهوم المؤشرات المعتمة، لنرَ كيف نكمل هذا النمط. يعلن ملف الترويسة عن وجود نوع، لكن ملف المصدر هو المكان الذي تعرّف فيه ما يحتويه بالفعل.
إليك الإعداد الكامل. أولًا، ملف الترويسة الذي يحتوي على التصريح المسبق فقط:
// counter.h
#ifndef COUNTER_H
#define COUNTER_H
typedef struct Counter Counter; // نوع غير مكتمل
Counter *create_counter(int start);
void free_counter(Counter *c);
#endif
بعد ذلك، يحتوي الملف المصدري على تعريف البنية الفعلي:
// counter.c
#include "counter.h"
#include <stdlib.h>
struct Counter {
int value; // مخفي عن الوصول من الخارج!
int step;
};
Counter *create_counter(int start) {
Counter *c = malloc(sizeof(Counter));
c->value = start;
c->step = 1;
return c;
}
void free_counter(Counter *c) {
free(c);
}
النقطة الأساسية: يظهر struct Counter { ... } في ملف .c فقط. أي ملف يتضمّن counter.h يعرف أن Counter موجود، لكنه لا يستطيع رؤية value أو step. ستؤدي محاولة كتابة c->value في main.c إلى خطأ في المترجم: فالأعضاء غير مرئية بالفعل.
يشكّل هذا الفصل أساس التغليف في C. والخطوة التالية هي إتاحة الوصول المنضبط من خلال دوال الحصول والتعيين.
التحدي
سهللننشئ وحدة Timer توضّح نمط المؤشر المعتم. ستتدرّب على إخفاء تعريف البنية داخل ملف المصدر، بحيث تصبح أعضاؤها الداخلية غير مرئية تمامًا لأي كود يستخدم وحدتك.
ستنشئ ثلاثة ملفات:
timer.h: هذه هي الواجهة العامة. صرّح عن نوع معتمTimerباستخدام تصريح تمهيدي فقط: لا تضع جسم البنية هنا! وصرّح أيضًا عن دالتين:create_timer(تأخذ عددًا صحيحًا للثواني وتُعيد مؤشرًا إلى Timer) وfree_timer(تأخذ مؤشرًا إلى Timer وتُجري التنظيف). استخدم حواجز التضمين مع الرمزTIMER_H.timer.c: هنا يكمن السر. عرّفstruct Timerالفعلية مع عضوين مخفيين:int secondsوint running(استخدم 1 للدلالة على أن المؤقّت يعمل، و0 للدلالة على أنه متوقف). نفّذ دالة الإنشاء لتخصيص ذاكرة للبنية، وتهيئةsecondsبالقيمة المقدّمة، وضبطrunningعلى 1. ونفّذ دالة الإتلاف لتحرير الذاكرة.main.c: استخدم وحدة Timer لإنشاء مؤقّت والتأكد من إنشائه بنجاح. بما أن أعضاء البنية مخفية، لا يمكنك الوصول إليها مباشرةً. وهذا هو الهدف بالكامل! اطبع ببساطة رسالة تؤكد الإنشاء، ثم حرّر المؤقّت واطبع رسالة تأكيد التنظيف.
ستتلقى مُدخلًا واحدًا: عدد الثواني (عدد صحيح) الذي ستُهيّئ به المؤقّت.
في ملفك الرئيسي، أنشئ مؤقّتًا باستخدام قيمة الثواني المقدّمة. اطبع رسالة إنشاء، ثم حرّر المؤقّت واطبع رسالة تأكيد.
اطبع الناتج بهذا التنسيق:
Timer created
Timer freedالفكرة الأساسية هنا هي أن main.c يستطيع التعامل مع مؤشرات Timer، لكنه لا يملك وسيلة للوصول إلى seconds أو running مباشرةً. ستؤدي محاولة كتابة t->seconds في main.c إلى خطأ من المترجم، لأن جسم البنية معرّف فقط في timer.c. وهذا هو التغليف الحقيقي: تفاصيل التنفيذ مخفية تمامًا عن مستخدمي وحدتك.
جرّب بنفسك
#include <stdio.h>
#include "timer.h"
int main() {
int seconds;
scanf("%d", &seconds);
// TODO: أنشئ مؤقتًا باستخدام قيمة الثواني المقدمة
// TODO: اطبع "Timer created"
// TODO: حرّر ذاكرة المؤقت
// TODO: اطبع "Timer freed"
return 0;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
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مشروع: رسّام الأشكال
نظرة عامة على المشروعتنفيذ الدائرةتنفيذ المستطيلاستخدام تعدد الأشكالحاوية الأشكالتدرّب بنفسك: مترجم C عبر الإنترنت