Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

قاعدة العضو الأول

جزء من قسم البرمجة كائنية التوجه في رحلة C على Coddy. الدرس 29 من 61.

عندما تقوم بتضمين بنية باعتبارها first member في بنية أخرى، يحدث أمر قوي: يكون عنوان ذاكرة البنية الخارجية مطابقًا لعنوان ذاكرة عضوها الأول. ويضمن معيار C ذلك.

تأمل مثالنا السابق:

typedef struct {
    int id;
} Parent;

typedef struct {
    Parent parent;  // العضو الأول
    int grade;
} Child;

عند إنشاء متغير Child، يوجد عضو Parent في بداية Child من memory تمامًا. وهذا يعني أن المؤشر إلى Child يشير إلى نفس address تمامًا الذي يشير إليه المؤشر إلى عضو Parent الخاص به.

Child c;
Child* child_ptr = &c;
Parent* parent_ptr = (Parent*)child_ptr;  // تحويل آمن!

يحمل كلا المؤشرين نفس address. يتيح لك ذلك تمرير Child* إلى أي function تتوقع Parent*:

void print_id(Parent* p) {
    printf("ID: %d\n", p->id);
}

// في main:
Child c;
c.parent.id = 42;
print_id((Parent*)&c);  // يعمل بشكل مثالي

هذه التقنية هي أساس الوراثة في C. يمكن لـ function مكتوبة للنوع الأساسي أن تعمل على أي نوع مشتق، ما دام النوع الأساسي embedded أولًا. إن cast آمن لأن memory layouts align perfectly.

challenge icon

التحدي

سهل

لنستكشف قاعدة first member من خلال بناء تسلسل هرمي بسيط للحيوانات. ستنشئ بنية Animal أساسية وبنية Dog مشتقة، ثم توضّح كيف يمكن تحويل مؤشر إلى Dog بأمان إلى مؤشر إلى Animal.

الفكرة الأساسية التي ستطبّقها: عندما تكون Animal هي first member في Dog، تشترك البنيتان في عنوان الذاكرة الابتدائي نفسه. وهذا يعني أنه يمكنك تمرير Dog* إلى أي function تتوقع Animal* من خلال تحويل المؤشر.

ستنظّم الشيفرة عبر ثلاثة ملفات:

  • animal.h: عرّف البنيتين مع حواجز include. يجب أن تحتوي بنية Animal على field واحدة: legs (عدد صحيح يمثّل عدد الأرجل). ويجب أن تضع بنية Dog بنية Animal المضمّنة باعتبارها first member وتضيف field باسم name (مصفوفة محارف مكوّنة من 50 محرفًا). أعلن أيضًا عن function باسم print_animal تأخذ Animal* parameter.
  • animal.c: نفّذ function print_animal. تعمل هذه function مع النوع الأساسي. وهي تعرف فقط Animal وتطبع عدد الأرجل التي يملكها الحيوان.
  • main.c: أنشئ متغيرًا من النوع Dog واملأ حقوله (كلًّا من legs الخاصة بالحيوان المضمّن واسم الكلب). ثم وضّح قاعدة first member من خلال تحويل Dog* الخاص بك إلى Animal* وتمريره إلى print_animal. اطبع أيضًا اسم الكلب بشكل منفصل لإظهار الصورة الكاملة.

ستتلقى مدخلين: اسم الكلب (سلسلة نصية) وعدد الأرجل (عدد صحيح).

يجب أن يبدو الإخراج بهذا الشكل:

Dog: Buddy
Legs: 4

حيث إن Buddy هو اسم الكلب و4 هو عدد الأرجل. اطبع اسم الكلب أولًا من main.c، ثم استدعِ print_animal باستخدام المؤشر المحوَّل لعرض عدد الأرجل.

يوضّح هذا كيف يمكن لـ function مكتوبة للنوع الأساسي (Animal) أن تعمل بسلاسة مع نوع مشتق (Dog) من خلال تحويل المؤشرات: وهو أساس الوراثة في C.

جرّب بنفسك

#include <stdio.h>
#include <string.h>
#include "animal.h"

int main() {
    // اقرأ الإدخال
    char name[50];
    int legs;
    scanf("%s", name);
    scanf("%d", &legs);
    
    // TODO: أنشئ متغير Dog
    
    // TODO: عيّن اسم الكلب باستخدام strcpy
    
    // TODO: عيّن عدد الأرجل (الوصول من خلال Animal المضمّن)
    
    // TODO: اطبع اسم الكلب بالصيغة: "Dog: <name>"
    
    // TODO: حوّل Dog* إلى Animal* واستدعِ print_animal
    // هذا يوضح قاعدة العضو الأول!
    
    return 0;
}
quiz iconاختبر نفسك

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

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

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