تعريف الـ 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
بعد ذلك، يحتوي الملف المصدر على تعريف البنية actual:
// 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 إلى حدوث خطأ من المترجم: إن members غير مرئية حقًا.
يُعَدّ هذا الفصل أساس التغليف في C. والخطوة التالية هي توفير وصول مُتحكَّم فيه من خلال دوال getter وsetter.
التحدي
سهللنبنِ وحدة Timer توضّح نمط المؤشر المعتم. ستتدرّب على إخفاء تعريف البنية داخل الملف المصدر، مما يجعل أعضائها الداخلية غير مرئية تمامًا لأي كود يستخدم وحدتك.
ستنشىء ثلاثة ملفات:
timer.h: هذه هي الواجهة العامة الخاصة بك. Declare نوعًا معتمًا هوTimerباستخدام تصريح Forward فقط: لا تضع جسم البنية هنا! Declare أيضًا دالتين:create_timer(تأخذ عددًا صحيحًا لعدد الثواني وتعيد مؤشرًا إلى Timer) وfree_timer(تأخذ مؤشرًا إلى Timer وتنفّذ عملية التنظيف). استخدم حواجز include بالرمزTIMER_H.timer.c: هنا يكمن الجزء السري. Define البنية الفعليةstruct Timerبعضوين مخفيين:int secondsوint running(استخدم 1 للدلالة على running و0 للدلالة على stopped). Implement المُنشئ لتخصيص البنية، وInitializesecondsبالقيمة provided، واضبطrunningعلى 1. Implement المُدمّر لتحرير الذاكرة.main.c: استخدم وحدة Timer الخاصة بك لإنشاء مؤقت والتأكد من أنه تم إنشاؤه بنجاح. بما أن أعضاء البنية مخفيون، لا يمكنك الوصول إليهم مباشرة. هذه هي الفكرة بالكامل! اطبع ببساطة رسالة تؤكد الإنشاء، ثم حرّر المؤقت واطبع رسالة تنظيف.
ستتلقى مُدخلًا واحدًا: عدد الثواني (عدد صحيح) الذي سيُستخدم لتهيئة المؤقت.
في ملفك الرئيسي، أنشئ مؤقتًا باستخدام قيمة الثواني provided. اطبع رسالة إنشاء، ثم حرّر المؤقت واطبع تأكيدًا.
اطبع الناتج بهذا التنسيق:
Timer created
Timer freedالفكرة الأساسية هنا هي أن main.c يستطيع العمل مع مؤشرات Timer، لكنه لا يملك أي وسيلة للوصول إلى seconds أو running مباشرة. ستؤدي محاولة كتابة t->seconds في main.c إلى خطأ من المُصرّف، لأن جسم البنية مُعرَّف فقط في timer.c. هذا هو التغليف الحقيقي: تفاصيل Implement مخفية تمامًا عن مستخدمي وحدتك.
جرّب بنفسك
#include <stdio.h>
#include "timer.h"
int main() {
int seconds;
scanf("%d", &seconds);
// TODO: أنشئ مؤقتًا بقيمة الثواني المُقدَّمة
// TODO: Print "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 عبر الإنترنت