Menu
CoddyTech

تعريف الـ 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. والخطوة التالية هي إتاحة الوصول المنضبط من خلال دوال الحصول والتعيين.

challenge icon

التحدي

سهل

لننشئ وحدة 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;
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم C عبر الإنترنت