פולימורפיזם – העמסה מול דריסה


העמקה והבהרות משלימות

למה נדרשת הבחנה חדה?

בשיעור הקודם הכרנו דוגמאות מגוונות (כולל עץ החלטות). עם זאת, שתי נקודות עלולות להישאר מבלבלות:

  1. מתי מתבצעת ההכרעה – האם בזמן הקומפילציה או בזמן הריצה?
  2. מה בעצם ההבדל הפדגוגי בין העמסת פעולות (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 נקבל באמת פולימורפיזם בזמן ריצה.

סיכום

  • העמסה = החלטה סטטית לפי חתימה.
  • דריסה = החלטה דינמית לפי סוג האובייקט בפועל.
  • תמיד נתחיל מהסוג המוצהר, נחפש התאמת חתימה, ואז נבדוק האם ההכרעה סטטית או דינמית.