בכיתה
1. המרת משתני ייחוס
משתנה ייחוס מתפקד כסוג של מצביע. למשל s1 מצביע על אובייקט מטיפוס Student ו- p1
מצביע על אובייקט מטיפוס Person:
אם במחלקת האב בלבד קיימת הפעולה Print:
()s1.Print יזמן את Print הקיימת במחלקת Person, כיוון ש- Student יורשת מ- Person את התכונות
והפעולות שהן public או protected.
אם בשתי המחלקות קיימת הפעולה Print:
()s1.Print יזמן את הפעולה Print הנמצאת במחלקה מטיפוס הייחוס. הייחוס של s1 הוא מטיפוס Student,
ולכן תוזמן הפעולה Print שבמחלקת Student.
ייחוס מטיפוס Person לאובייקט מטיפוס Student:
1. השלימו ליום ו' הקרוב כל מה שלא הספקתם בכיתה (קריאה, הבנה, סעיף 2 והתרגיל מסעיף 3).
2. הגשת מחלקת השירות המעודכנת Array.
1. המרת משתני ייחוס
משתנה ייחוס מתפקד כסוג של מצביע. למשל s1 מצביע על אובייקט מטיפוס Student ו- p1
מצביע על אובייקט מטיפוס Person:
Person p1 = new Person();
Student s1 = new Student();
נניח ש- Student יורש מ- Person.
()s1.Print יזמן את Print הקיימת במחלקת Person, כיוון ש- Student יורשת מ- Person את התכונות
והפעולות שהן public או protected.
אם בשתי המחלקות קיימת הפעולה Print:
()s1.Print יזמן את הפעולה Print הנמצאת במחלקה מטיפוס הייחוס. הייחוס של s1 הוא מטיפוס Student,
ולכן תוזמן הפעולה Print שבמחלקת Student.
ייחוס מטיפוס Person לאובייקט מטיפוס Student:
Person p10 = new Student();
אם קיימת הפעולה Print בשתי המחלקות, s1.Print יזמן את הפעולה Print הנמצאת במחלקת Person.
וזה למרות ש- s1 מצביע לאובייקט מטיפוס Student.
מדוע תופעל Print ממחלקת Person אם s1 מצביע על אובייקט מטיפוס Student?
כיוון שהמצביע s1 הוא מטיפוס Person! והטיפוס ממנו הוגדר הייחוס, הוא שקובע איזו פעולה Print תופעל.
מתי נגדיר מצביע מטיפוס אב, המפנה לאובייקט מטיפוס בן?
אם ברצוננו לשמור באוסף (למשל: מערך/רשימה/מחסנית...) את כל העובדים בביה"ס:
מורים, תלמידים ועובדים שונים, הרי שכל האובייקטים בביה"ס הם מטיפוס Student, Teacher או Worker.
כל האובייקטים הללו הם ממחלקות הנגזרות ממחלקת Person. ולכן על האוסף להיות מטיפוס... Person.
מורים, תלמידים ועובדים שונים, הרי שכל האובייקטים בביה"ס הם מטיפוס Student, Teacher או Worker.
כל האובייקטים הללו הם ממחלקות הנגזרות ממחלקת Person. ולכן על האוסף להיות מטיפוס... Person.
זו הסיבה שנרצה מצביע מטיפוס Person לאובייקט או לאובייקטים מטיפוסים של מחלקות הנגזרות מ- Person.
פולימורפיזם - היכולת לתת מימוש שונה לאותה הפעולה
אם נרצה לעבור על כל האנשים באוסף ולהדפיס את שמם ואת הסטטוס שלהם, הרי שעבור
האובייקט w1 נרצה להדפיס שהסטטוס שלו הוא "עובד בבית הספר". עבור אובייקט s1 נרצה להדפיס
שהסטטוס שלו הוא "תלמיד בבית הספר", עבור t1 נרצה להדפיס שהסטטוס שלו הוא "מורה בבית הספר".
בכל אחת מהמחלקות הללו קיימת הפעולה ()GetStatus. אבל, האוסף הוא מטיפוס Person. ולכן זימון
הפעולה GetStatus על כל אובייקט, תחפש את הפעולה הזו במחלקת Person
(כי האוסף הוא מטיפוס Person). את זה אנו לא רוצים. נרצה שעבור t1 תזומן הפעולה GetStatus
בגרסה בה היא נכתבה במחלקת Teacher.
מימוש הפולימורפיזם באמצעות מתודה וירטואלית:
האובייקט w1 נרצה להדפיס שהסטטוס שלו הוא "עובד בבית הספר". עבור אובייקט s1 נרצה להדפיס
שהסטטוס שלו הוא "תלמיד בבית הספר", עבור t1 נרצה להדפיס שהסטטוס שלו הוא "מורה בבית הספר".
בכל אחת מהמחלקות הללו קיימת הפעולה ()GetStatus. אבל, האוסף הוא מטיפוס Person. ולכן זימון
הפעולה GetStatus על כל אובייקט, תחפש את הפעולה הזו במחלקת Person
(כי האוסף הוא מטיפוס Person). את זה אנו לא רוצים. נרצה שעבור t1 תזומן הפעולה GetStatus
בגרסה בה היא נכתבה במחלקת Teacher.
מימוש הפולימורפיזם באמצעות מתודה וירטואלית:
בכדי לממש פולימורפיזם, יש להגדיר תחילה את הפעולה במחלקת הבסיס כוירטואלית (virtual).
במקרה שלנו, נגדיר את הפעולה GetStatus במחלקת Person כ- virtual.
במחלקות היורשות את Peson: המחלקות Worker, Teacher, Student נדרוס אותה באמצעות override.
ואז, כאשר ניצור ייחוס ממחלקת הבסיס (למשל מערך ממחלקת Person), ונזמן את הפעולה GetStatus,
הרי שתופעל GetStatus הנמצאת במחלקת האובייקט, ולא מחלקת המצביע. כלומר, המצביע של האוסף
הוא מטיפוס Person, אך האובייקט t1 הוא מטיפוס Teacher, ולכן תזומן GetStatus כפי שהיא כתובה
במחלקת Teacher.
הרי שתופעל GetStatus הנמצאת במחלקת האובייקט, ולא מחלקת המצביע. כלומר, המצביע של האוסף
הוא מטיפוס Person, אך האובייקט t1 הוא מטיפוס Teacher, ולכן תזומן GetStatus כפי שהיא כתובה
במחלקת Teacher.
המרה של משתני ייחוס (Casting)
הקומפיילר ב- NET. מתיר רק המרות לאורך ההיררכיה של המחלקות הנגזרות.
קיימים שני סוגים של המרות:
קיימים שני סוגים של המרות:
א. המרה כלפי מעלה בהיררכיה Upcasting
ב. המרה כלפי מטה בהיררכיה Downcasting
דוגמה1 (ללא הגדרת virtual עבור הפעולה Print הנמצאת ב- Person)
הקוד:
Person p100 = new Student();
p100.Print();
התוצאה:
תזומן Print הנמצאת במחלקת Peston. זו המרה כלפי מעלה (Upcasting).
דוגמה2 (עם הגדרת Print שבמחלקת Person כוירטואלית)
הקוד:
Person p200 = new Student();
p200.Print();
התוצאה:
תזומן Print הנמצאת במחלקת Student. זו המרה כלפי מטה (Downcasting).
המרה כלפי מטה
דוגמה נוספת להמרה כלפי מטה, יכולה להיראות כך:
הקוד:
//Student מפנה לאובייקט מטיפוס Person שהוא מטיפוס p123 המצביע
Person p123 = new Student();
Student s = (Student)p123;
התוצאה:
המצביע s שהוא מטיפוס Student מפנה לאובייקט בשם s1 שהוא מטיפוס Student.
הסבר:
מותר היה לנו לבצע המרה של p123 (שנוצר כמצביע מטיפוס Person) כלפי מטה לטיפוס Student, כיוון
שבמקור p123 בכל מקרה הצביע לאובייקט מטיפוס Student. ההמרה בסך הכל שינתה את סוג הייחוס
מ- Person ל- Student. האובייקט אליו הפנה p123 בכל מקרה, היה כל הזמן מטיפוס Student.
המרה כלפי מעלה לעומת המרה כלפי מטה
המרה כלפי מטה היא מסוכנת, כיוון שאם היא לא תעשה באופן מפורש, היא עלולה לגרום לשגיאה
בזמן ריצת התוכנית. המרה מפורשת כלפי מטה נראית, למשל, כך:
בזמן ריצת התוכנית. המרה מפורשת כלפי מטה נראית, למשל, כך:
Student s = (Student)p123;
כאשר p123, לפני ההמרה, היה ייחוס מטיפוס Person.
ההמרה כלפי מעלה היא בטוחה, כיוון שתמיד אפשר להסתכל על עצם מסוג תת-מחלקה כאילו
הוא עצם של מחלקת העל. למשל, תמיד ניתן להפעיל על אובייקט Student את הפעולה ToString
השייכת למחלקת Person. אבל לא תמיד בטוח להפעיל את ToString של מחלקת Student
על אובייקט מטיפוס Person.
הוא עצם של מחלקת העל. למשל, תמיד ניתן להפעיל על אובייקט Student את הפעולה ToString
השייכת למחלקת Person. אבל לא תמיד בטוח להפעיל את ToString של מחלקת Student
על אובייקט מטיפוס Person.
2. האופרטור is
קראו באינטרנט אודות האופרטור is ב- #C. לאחר מכן, הסבירו מה עושה הקוד הבא:
Person[] arr = new Person[5];
//הניחו כי ביצענו השמה של אובייקטים שונים מהטיפוסים
//Worker, Student, Teacher
//.לתוך 5 איברי המערך
//לולאה למעבר על כל האנשים השייכים לבית הספר
for(int i = 0; i<arr.Length; i++)
{
//_______________________________ אם
if(arr[i] is Teacher)
//_________________________________ הדפס את
Console.WriteLine( ((Teacher)arr[i]).GetProfession() );
}
לבית
3. תרגיל SchoolEntities בנושא דריסת פעולות בהיררכיית הורשה ושימוש באופרטור is
1. השלימו ליום ו' הקרוב כל מה שלא הספקתם בכיתה (קריאה, הבנה, סעיף 2 והתרגיל מסעיף 3).
2. הגשת מחלקת השירות המעודכנת Array.