عملية الـ Upcasting
جزء من قسم البرمجة كائنية التوجه في رحلة C على Coddy. الدرس 31 من 61.
إن التحويل إلى النوع الأساسي هو التعامل مع نوع محدد (مشتق) على أنه نوعه الأكثر عمومية (الأساسي). في نموذج التركيب في C، يعني هذا تمرير مؤشر إلى بنية تضمّن نوعًا أساسيًا إلى دالة تتوقع النوع الأساسي.
تأمل بنية أساسية 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); // الناتج: 50هذا هو التحويل إلى نوع أعمّ: ننتقل «إلى الأعلى» من نوع محدد إلى نوع عام. لا تعرف الدالة accelerate أنها تعمل مع Car؛ فهي لا ترى سوى Vehicle. يتيح لك هذا كتابة شيفرة قابلة لإعادة الاستخدام تعمل على النوع الأساسي، مع قبول أي نوع مشتق يتضمنه.
التحدي
سهللنبنِ نظام نقل بسيطًا يوضّح عملية التحويل إلى النوع الأساسي. ستنشئ نوعًا أساسيًا Vehicle ونوعًا أكثر تحديدًا Motorcycle، ثم تبيّن كيف يمكن لدالة عامة أن تعمل مع كليهما من خلال تحويل المؤشرات.
تكمن قوة التحويل إلى النوع الأساسي في أنه يمكنك كتابة دوال للنوع الأساسي، وستعمل بسلاسة مع أي نوع مشتق يضمّه. دراجتك النارية «هي مركبة»، لذا ينبغي أن تتمكن أي دالة تتوقع 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وتهيئة جميع حقولها. ثم وضّح التحويل إلى النوع الأساسي باستدعاء الدالة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: وضّح التحويل إلى النوع الأب باستدعاء boost
// حوّل Motorcycle* إلى Vehicle* لتمريره إلى الدالة boost
// TODO: اطبع معلومات الدراجة النارية
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 عبر الإنترنت