تضمين الـ Struct
جزء من قسم البرمجة كائنية التوجه في رحلة C على Coddy. الدرس 28 من 61.
في اللغات كائنية التوجه مثل C++ أو Java، يتيح الوراثة لفئة اكتساب الخصائص من فئة أب. لا تحتوي C على وراثة مضمّنة، لكن يمكننا محاكاتها باستخدام تقنية تُسمّى التركيب: وضع بنية struct داخل بنية أخرى.
الفكرة بسيطة: إذا كان Child يحتاج إلى جميع خصائص Parent، فإننا نضمّن بنية Parent كعضو في Child.
typedef struct {
int id;
char name[50];
} Parent;
typedef struct {
Parent parent; // هيكل مضمّن
int grade;
} Child;هنا، يحتوي Child على كل ما لدى Parent، بالإضافة إلى حقل grade الخاص به. هذا هو التركيب: إذ إن الابن «يمتلك» أبًا بدلًا من أن «يكون» أبًا، لكن التأثير مشابه للتوريث.
للوصول إلى أعضاء parent من خلال نسخة Child، تستخدم معامل dot مرتين:
Child c;
c.parent.id = 101;
c.parent.name[0] = 'A';
c.grade = 5;يشكّل هذا النمط الأساس لبناء التسلسلات الهرمية للأنواع في C. ومن خلال تضمين بنية base باعتبارها first member، نفتح المجال أمام تقنيات قوية سنستكشفها في الدروس القادمة.
التحدي
سهللنَبْنِ نظامًا بسيطًا لإدارة الموظفين يوضّح تضمين البُنى: أساس الوراثة في C.
ستنشئ تسلسلاً هرميًا حيث يحتوي Employee على Person. وهذا يحاكي كيفية عمل الوراثة: employee "is a" person مع information إضافية متعلقة بالوظيفة. ومن خلال تضمين بنية Person داخل Employee، تحصل على جميع خصائص person بالإضافة إلى الحقول الخاصة بـ employee.
ستنظّم التعليمات البرمجية عبر ثلاثة ملفات:
types.h: عرّف البنيتين هنا مع حواجز التضمين. أولًا، أنشئ بنيةPersonتحتوي على حقلين:name(مصفوفة من character تتكون من 50 character) وage(عدد صحيح). ثم عرّف بنيةEmployeeالتي تضمّنPersonكأول member لها، وتضيف حقلemployee_id(عددًا صحيحًا).types.c: Implement function تسمىprint_employeeتأخذ pointer إلىEmployeeوتطبع information الخاصة به. استخدم صيغة dot/arrow المتسلسلة للوصول إلى data الخاصة بـ person المضمّنة، كما تعلّمت.main.c: أنشئ variable من نوعEmployee، وPopulate جميع حقوله (بما في ذلك name وage الخاصين بـ person المضمّن)، واستخدم print function لعرض information.
ستتلقى ثلاثة مدخلات: name الخاص بـ employee (string)، وage الخاص به (integer)، وemployee ID الخاص به (integer).
يجب أن تُخرج function print_employee information الخاصة بـ employee بالتنسيق التالي:
Employee: Alice
Age: 28
ID: 1001حيث إن Alice هو name، و28 هو age، و1001 هو employee ID من مدخلاتك.
تذكّر الوصول إلى members الخاصة بالبنية المضمّنة من خلال parent member؛ فمثلًا، للوصول إلى name، ستتنقّل أولًا عبر member person.
جرّب بنفسك
#include <stdio.h>
#include <string.h>
#include "types.h"
int main() {
// اقرأ الإدخال
char name[50];
int age;
int employee_id;
fgets(name, 50, stdin);
name[strcspn(name, "\n")] = '\0'; // أزل السطر الجديد
scanf("%d", &age);
scanf("%d", &employee_id);
// TODO: أنشئ متغير Employee
// TODO: املأ اسم وعمر الشخص المضمّن
// Hint: استخدم strcpy للاسم، والوصول عبر employee.person.name
// TODO: عيّن الـ employee_id
// TODO: استدعِ print_employee مع مؤشر إلى الـ employee الخاص بك
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 عبر الإنترنت