המרה כלפי מעלה
חלק מהיחידה תכנות מונחה עצמים במסלול ה-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;
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
4כימוס
המושג של מצביעים אטומיםהגדרת מבנים אטומיםפונקציות Get ו-Setאימות ב-Settersסיכום: הקופסה הסודית2אובייקטים ומתודות
מבנים כאובייקטיםמצביע 'Self'נכונות constמצביע לעומת ערךמתודות עזרחזרה: מנהל נקודות5פרויקט: חשבון בנק פשוט
הגדרת הפרויקטמימוש החשבוןתרגלו בעצמכם: קומפיילר C אונליין