Menu
Coddy logo textTech

המרה כלפי מעלה

חלק מהיחידה תכנות מונחה עצמים במסלול ה-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. כך אפשר לכתוב קוד שניתן לעשות בו שימוש חוזר, שפועל על טיפוס הבסיס ומקבל כל טיפוס נגזר שמכיל אותו.

challenge icon

אתגר

קל

בואו נבנה מערכת תחבורה פשוטה שמדגימה המרה כלפי מעלה בפעולה. תיצרו טיפוס בסיסי 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;
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר C אונליין