למה נדרשת הבחנה חדה?
בשיעור הקודם הכרנו דוגמאות מגוונות (כולל עץ החלטות). עם זאת, שתי נקודות עלולות להישאר מבלבלות:
- מתי מתבצעת ההכרעה – האם בזמן הקומפילציה או בזמן הריצה?
- מה בעצם ההבדל הפדגוגי בין העמסת פעולות (Overloading) לבין דריסת פעולות (Overriding)?
שלב ההכרעה
flowchart TD
Start["קריאת פעולה בקוד"] --> CheckDeclared["בדיקת סוג *מוצהר* של המשתנה"]
CheckDeclared --> Overload["חיפוש פעולות תואמות חתימה (Overloading)"]
Overload -->|נמצאה חתימה מתאימה| VirtualCheck{"האם הפעולה virtual/override?"}
Overload -->|לא נמצאה| Error["שגיאת קומפילציה"]
VirtualCheck -->|כן| Runtime["הכרעה בזמן ריצה: נקבע לפי סוג האובייקט בפועל"]
VirtualCheck -->|לא| Compiletime["הכרעה בזמן קומפילציה: נקבע לפי הסוג המוצהר"]
- אם אין התאמה בחתימה → שגיאת קומפילציה.
- אם יש התאמה ואין Virtual/Override → הקומפיילר סוגר עניין (בחירה סטטית).
- אם יש Virtual/Override → ההכרעה נדחית לריצה (בחירה דינמית).
טבלה מסכמת: העמסה מול דריסה
מאפיין | העמסה (Overloading) | דריסה (Overriding) |
---|---|---|
מיקום | באותה מחלקה | בין מחלקת בסיס למחלקת ירושה |
שם פעולה | זהה | זהה |
חתימה | שונה (פרמטרים שונים) | זהה לחלוטין |
מועד ההכרעה | בזמן קומפילציה | בזמן ריצה (אם virtual/override ) |
מטרת שימוש | גמישות קריאה – אותו שם לפעולות שונות | התאמת התנהגות – מחלקה יורשת משנה יישום |
אפשרי עם static? | כן | לא (דריסה חלה רק על virtual/abstract) |
הערה על ToString
שאלת תלמיד נפוצה: למה אם מגדירים ToString
בלי override זה עדיין עובד ב-Console.WriteLine?
- הסיבה: כל מחלקה ב-C# בכל מקרה יורשת מ-
object
שבו קיימת פעולהToString()
. - אם מגדירים פעולה חדשה
ToString
בלי override, זו הסתרה (Hiding) ולא דריסה. - במקרה זה, קריאה מפורשת ל-
obj.ToString()
תפעל, אבל קריאה מרומזת (למשל"" + obj
) תשתמש רק בגרסה הדרוסה הרשמית. לכן רק עם override נקבל באמת פולימורפיזם בזמן ריצה.
סיכום
- העמסה = החלטה סטטית לפי חתימה.
- דריסה = החלטה דינמית לפי סוג האובייקט בפועל.
- תמיד נתחיל מהסוג המוצהר, נחפש התאמת חתימה, ואז נבדוק האם ההכרעה סטטית או דינמית.