عملية الـ Upcasting
جزء من قسم البرمجة كائنية التوجه في رحلة C على Coddy. الدرس 31 من 61.
الرفع إلى نوع أعم هو التعامل مع نوع محدد (مشتق) على أنه نوع أكثر عمومية (أساسي). في نموذج التركيب في C، يعني هذا تمرير مؤشر إلى بنية struct تدمج نوعًا أساسيًا إلى function تتوقع النوع الأساسي.
لنفترض وجود البنية الأساسية Vehicle وبنية Car التي تحتوي عليها:
typedef struct {
int speed;
} Vehicle;
typedef struct {
Vehicle vehicle; // الأساس كعضو أول
int doors;
} Car;تخيّل الآن دالة عامة تعمل مع أي مركبة:
void accelerate(Vehicle* v, int amount) {
v->speed += amount;
}بفضل قاعدة العضو first، يمكننا تمرير Car* إلى هذه الدالة عن طريق تحويله إلى Vehicle*:
Car my_car = {{0}, 4}; // speed=0, doors=4
accelerate((Vehicle*)&my_car, 50);
printf("Speed: %d\n", my_car.vehicle.speed); // الناتج: 50هذا هو الرفع النوعي: نحن نتحرك إلى «أعلى» من نوع محدد إلى نوع عام. لا تعرف الدالة accelerate أنها تعمل مع Car؛ فهي ترى فقط Vehicle. يتيح لك ذلك كتابة تعليمات برمجية قابلة لإعادة الاستخدام تعمل على النوع الأساسي، مع قبول أي نوع مشتق يضمّه.
التحدي
سهللنَبْنِ نظام نقل بسيطًا يوضّح عملية الرفع إلى النوع الأساسي (upcasting) عمليًا. ستنشئ نوعًا أساسيًا Vehicle ونوعًا أكثر تخصيصًا Motorcycle، ثم توضّح كيف يمكن لـ function عامة العمل مع كليهما من خلال تحويل المؤشرات.
تكمن قوة الرفع إلى النوع الأساسي في أنه يمكنك كتابة دوال للنوع الأساسي، وستعمل بسلاسة مع أي نوع مشتق يضمّنه. دراجتك النارية «هي مركبة»، ولذلك ينبغي لأي دالة تتوقع Vehicle* أن تتمكن من معالجتها.
ستنظّم شيفرتك عبر ثلاثة ملفات:
vehicle.h: عرّف تسلسل البنى الخاص بك مع حواجز التضمين. أنشئ بنيةVehicleبحقلين:speed(عدد صحيح للسرعة الحالية) وmax_speed(عدد صحيح للسرعة القصوى للمركبة). ثم عرّف بنيةMotorcycleالتي تضمّنVehicleباعتبارها أول عضو فيها، وتضيف الحقلhas_sidecar(عددًا صحيحًا، حيث يعني 1 نعم و0 لا). صرّح بدالتين:boostالتي تستقبلVehicle*ومقدارًا لزيادة السرعة، وprint_motorcycleالتي تستقبلMotorcycle*.vehicle.c: نفّذ كلتا الدالتين. ينبغي لدالةboostأن تزيد سرعة المركبة بالمقدار المعطى، لكن تحدّها عندmax_speed؛ فإذا كانت السرعة الجديدة ستتجاوز الحد الأقصى، فاضبطها علىmax_speedبدلًا من ذلك. وينبغي لدالةprint_motorcycleعرض جميع معلومات الدراجة النارية، بما في ذلك بيانات المركبة المضمّنة فيها.main.c: أنشئMotorcycleوinitialize جميع حقولها. ثم Demonstrate الرفع إلى النوع الأساسي عبر استدعاء دالةboost: حوّلMotorcycle*إلىVehicle*لتمريره إلى هذه الدالة العامة. بعد زيادة السرعة، اطبع معلومات الدراجة النارية لرؤية النتيجة.
ستتلقى أربعة مدخلات: السرعة الأولية للدراجة النارية، والسرعة القصوى لها، وما إذا كان لديها صندوق جانبي (1 أو 0)، ومقدار الزيادة.
ينبغي أن تبدو مخرجاتك كما يلي:
Speed: 75
Max Speed: 120
Sidecar: Yesحيث إن 75 هي السرعة بعد الزيادة (السرعة الأولية 50 + الزيادة 25)، و120 هي السرعة القصوى، وتشير Yes أو No إلى ما إذا كانت الدراجة النارية تحتوي على صندوق جانبي. إذا كانت الزيادة ستدفع السرعة إلى ما بعد max_speed، فينبغي تحديد السرعة عند max_speed.
الفكرة الأساسية هنا هي أن boost لا يعرف شيئًا عن الدراجات النارية. فهو يعمل فقط مع Vehicle. ومع ذلك، ومن خلال الرفع إلى النوع الأساسي، يمكن لدراجتك النارية استخدام هذه الدالة العامة لتعديل بيانات المركبة المضمّنة فيها.
جرّب بنفسك
#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;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
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 عبر الإنترنت