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

عملية الـ Upcasting

جزء من قسم Object Oriented Programming في رحلة C على Coddy — الدرس 31 من 61.

التحويل التصاعدي (Upcasting) هو عملية معاملة نوع محدد (مشتق) كنوعه الأكثر عمومية (أساسي). في نموذج التركيب (composition model) الخاص بلغة C، يعني هذا تمرير مؤشر (pointer) إلى struct يدمج نوعاً أساسياً إلى دالة تتوقع النوع الأساسي.

ضع في اعتبارك الهيكل الأساسي Vehicle و Car الذي يحتويه:

typedef struct {
    int speed;
} Vehicle;

typedef struct {
    Vehicle vehicle;  // الأساس كعضو أول
    int doors;
} Car;

تخيل الآن دالة عامة تعمل مع أي مركبة:

void accelerate(Vehicle* v, int amount) {
    v->speed += amount;
}

بفضل قاعدة العضو الأول، يمكننا تمرير Car* إلى هذه الدالة عن طريق تحويله إلى Vehicle*:

Car my_car = {{0}, 4};  // speed=0, doors=4
accelerate((Vehicle*)&my_car, 50);
printf("Speed: %d\n", my_car.vehicle.speed);  // Output: 50

هذا هو التحويل للأعلى (upcasting) — نحن ننتقل "للأعلى" من نوع محدد إلى نوع عام. الدالة accelerate لا تعرف أنها تعمل مع Car؛ بل ترى فقط Vehicle. يتيح لك ذلك كتابة كود قابل لإعادة الاستخدام يعمل على النوع الأساسي مع قبول أي نوع مشتق يقوم بتضمينه.

challenge icon

التحدي

سهل

لنقم ببناء نظام نقل بسيط يوضح عملية الـ upcasting (التحويل التصاعدي) بشكل عملي. ستقوم بإنشاء نوع أساسي Vehicle ونوع أكثر تخصصاً وهو Motorcycle، ثم توضح كيف يمكن لدالة عامة أن تعمل مع كليهما من خلال تحويل المؤشرات (pointer casting).

تكمن قوة الـ upcasting في أنه يمكنك كتابة دوال للنوع الأساسي، وستعمل بسلاسة مع أي نوع مشتق يتضمنه. فالدراجة النارية "هي" مركبة، لذا فإن أي دالة تتوقع Vehicle* يجب أن تكون قادرة على معالجتها.

ستقوم بتنظيم الكود الخاص بك عبر ثلاثة ملفات:

  • vehicle.h: قم بتعريف هيكل الـ structs الخاص بك مع استخدام حواجز التضمين (include guards). أنشئ struct باسم Vehicle يحتوي على حقلين: speed (عدد صحيح للسرعة الحالية) و max_speed (عدد صحيح للسرعة القصوى للمركبة). ثم قم بتعريف struct باسم Motorcycle يدمج Vehicle كعضو أول فيه ويضيف حقل has_sidecar (عدد صحيح، حيث 1 يعني نعم و 0 يعني لا). قم بالتصريح عن دالتين: boost التي تأخذ Vehicle* ومقداراً لزيادة السرعة، و print_motorcycle التي تأخذ Motorcycle*.
  • vehicle.c: قم بتنفيذ كلتا الدالتين. يجب أن تقوم دالة boost بزيادة سرعة المركبة بالمقدار المحدد، ولكن مع وضع حد أقصى هو max_speed—إذا كانت السرعة الجديدة ستتجاوز الحد الأقصى، فاجعلها تساوي max_speed بدلاً من ذلك. يجب أن تعرض دالة print_motorcycle جميع معلومات الدراجة النارية بما في ذلك بيانات المركبة المدمجة فيها.
  • main.c: قم بإنشاء Motorcycle وتهيئ جميع حقولها. ثم وضح عملية الـ upcasting من خلال استدعاء دالة boost—قم بتحويل Motorcycle* إلى Vehicle* لتمريره إلى هذه الدالة العامة. بعد عملية التعزيز (boosting)، قم بطباعة معلومات الدراجة النارية لرؤية النتيجة.

ستتلقى أربعة مدخلات: السرعة الابتدائية للدراجة النارية، سرعتها القصوى، ما إذا كانت تحتوي على عربة جانبية (1 أو 0)، و مقدار التعزيز (boost amount).

يجب أن يبدو مخرجك كالتالي:

Speed: 75
Max Speed: 120
Sidecar: Yes

حيث 75 هي السرعة بعد التعزيز (الابتدائية 50 + التعزيز 25)، و 120 هي السرعة القصوى، و Yes أو No تشير إلى ما إذا كانت الدراجة النارية تحتوي على عربة جانبية. إذا كان التعزيز سيدفع السرعة لتتجاوز max_speed، فيجب أن تقتصر السرعة على max_speed.

الدرس الأساسي هنا هو أن boost لا تعرف شيئاً عن الدراجات النارية—فهي تعمل فقط مع Vehicle. ومع ذلك، من خلال الـ upcasting، يمكن لدراجتك النارية استخدام هذه الدالة العامة لتعديل بيانات المركبة المدمجة فيها.

ورقة مرجعية

يعامل الـ Upcasting النوع المحدد (المشتق) كنوعه الأكثر عمومية (الأساسي) عن طريق تمرير مؤشر (pointer) إلى هيكل (struct) يتضمن نوعاً أساسياً إلى دالة تتوقع النوع الأساسي.

قم بتعريف هيكل أساسي (base struct) وهيكل مشتق (derived struct) يتضمنه كعضو أول:

typedef struct {
    int speed;
} Vehicle;

typedef struct {
    Vehicle vehicle;  // الأساس كعضو أول
    int doors;
} Car;

أنشئ دالة تعمل مع النوع الأساسي:

void accelerate(Vehicle* v, int amount) {
    v->speed += amount;
}

قم بتحويل مؤشر النوع المشتق إلى مؤشر النوع الأساسي لاستدعاء الدالة:

Car my_car = {{0}, 4};  // speed=0, doors=4
accelerate((Vehicle*)&my_car, 50);
printf("Speed: %d\n", my_car.vehicle.speed);  // المخرجات: 50

يتيح لك ذلك كتابة كود قابل لإعادة الاستخدام يعمل على النوع الأساسي مع قبول أي نوع مشتق يتضمنه.

جرّب بنفسك

#include <stdio.h>
#include "vehicle.h"

int main() {
    int initial_speed, max_speed, has_sidecar, boost_amount;
    
    // قراءة المدخلات
    scanf("%d", &initial_speed);
    scanf("%d", &max_speed);
    scanf("%d", &has_sidecar);
    scanf("%d", &boost_amount);
    
    // TODO: إنشاء Motorcycle وتهيئة جميع حقولها
    // تذكر: Motorcycle تتضمن Vehicle كعضو أول لها
    
    // TODO: توضيح الـ upcasting من خلال استدعاء boost
    // قم بتحويل Motorcycle* إلى Vehicle* لتمريره إلى دالة boost
    
    // TODO: طباعة معلومات الـ motorcycle
    
    return 0;
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming