4.3.2.4. Universal Polymorphism

4.3.2.4.1.    Parametric Polymorphism

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

Ad hoc לעומת Parametric:

Overloading: פעולה מינימלית – למספר קטן של הפשטות קיים מזהה זהה.

אינו מגביר את יכולת הביטוי של השפה – ניתן להיפטר מ-overloading על ידי נתינת שמות שונות להפשטות השונות המתאימות לו. הקשר בין ההפשטות השונות לא בהכרח קיים.

Coercion: פעולה גדולה יותר – אותה פונקציה יכולה לשמש למספר מטרות. עם זאת מספר המטרות הינו מוגבל, והערך המוחזר הינו זהה. הקשר בין הצורות מוכתב על ידי ה-coercions, וקשר זה אינו חלק מהשגרה.

Polymorphic Type (universal) – להפשטה יחידה יש מספר גדול של משפחות של סוגים קשורים. ההפשטה פועלת באופן אחיד על הארגומנטים שלה ללא תלות בסוגם. מוסיפה כוח ביטוי לשפה על ידי יצירת פונקציות היכולות לקבל מספר לא מוגבל של סוגים.

Parametric Type Polymorphism In Pascal: האופרטורים +, *, -, פעולות איחוד וחיתוך קבוצות הינם כולם Parametric Type Polymorphism. הפרוצדורות new, dispose יוצרות משתנה מסוג כלשהו. הערך nil הוא ערך מצביע לסוג כלשהו. [] הקבוצה הריקה מתאימה לכל סוג.

Universal pointer in C: בשפת C מצביע מסוג void* יכול להיות מושם לתוך כל מצביע אחר, וכן כל מצביע יכול להיות מושם בתוך משתנה מסוג void*. עובדה זו ב-C איננה ad hoc אלא parametric polymorphism, מכיוון שהיא מוגדרת אוטומטית לכל מצביע.

C++ Templates: Templates זוהי הדרך של שפת C++ לממש parametric polymorphism. בעזרת התבניות אנחנו מסוגלים ליצור פונקציות/מחלקות המקבלות פרמטר מסוג כלשהו שיוגדר בהמשך, לפי הצורך.



4.3.2.4.2.    Inclusion Polymorphism

Inclusion Polymorphism זהו הסוג השני של Universal Polymorphism. סוג זה נובע מקשרי הכללה (הורשה) בין סוגים או קבוצות של ערכים.

תזכורת:

סוג הוא קבוצת ערכים להם פעולות משותפות. תת סוג (sub type) הוא תת קבוצה של ערכים.

דוגמאות:

  • "מכוניות" הן תת סוג של "כלי רכב".
  • "סטודנטים" ו-"מרצים" הם תת סוג של "בני אדם".

Subtype:

  • הגדרה 1: הסוג A הוא תת סוג של B אם plot:\[A \subseteq B\].
  • הגדרה 2: הסוג A הוא תת סוג של B אם כל ערך ב-A יכול להיות מומר (coerced) לערך ב-B.
  • דגש: תת סוג איננו סוג – ערך יכול להיות שייך לסוג אחד בלבד, אולם ערך יכול להיות שייך למספר תתי סוגים.

Subclassing:

  • המטרה: שימוש חוזר בקוד.
  • זהו מנגנון של מימוש.
  • ניתן לומר שזה "תכנות אינקרמנטלי".

ב-Strict Inheritance, מתקיים כי Subclassing plot:$
 \Leftarrow $ Subtyping. פעולות המוגדרות על מחלקת הבסיס מותרות על המחלקות הנורשות ממנה.

רוב ה- Inclusion Polymorphism נובעים מ-subtypes.



כאשר אנחנו מדברים על Inclusion Polymorphism, אנחנו מדברים על שני אלמנטים:

  • מתודות פולימורפיות.
  • אובייקטים פולימורפיים.

דוגמא למתודה פולימורפית במחלקות:

Employee E;

Manager M;

E.raise_salary(10);     // OK

M.raise_salary(10);     // OK

E.is_manager_of(...);   // Error

E.is_manager_of(10);    // OK

המתודה raise_salary היא פולימורפית – היא מסוגלת לקבל את כל תתי הסוגים (תתי המחלקות) של המחלקה Employee.

דוגמאות לאובייקטים פולימורפיים:

  • Pascal: הערך nil שייך לכל סוגי המצביעים.
  • C: הערך 0 הוא פולימורפי – שייך לכל סוגי המצביעים.
  • C++: הסוג void* הוא סוג-על לכל סוגי המצביעים. this הוא אובייקט פולימורפי – יכול להצביע לסוגים שונים בזמנים שונים.
  • Smalltalk: כל המשתנים בשפה הינם פולימורפיים מכיוון שהם יכולים להכיל ערכים מסוגים שונים בזמנים שונים.

מאת: ניצן

Borland style vptr

לפי מה שאני מכיר:
"חסרון בגישה זו: גם כאשר איננו משתמשים ב-dynamic binding – אנחנו משלמים במקום"
לא נכון , עבור מחלקה A שאין לה מתודות דינמיות לא יווצר כלל המצביע, ולמשל עבור מחלקה B שיורשת מA פשוט נוסיף בהתחלה את המצביע, ואחרי הבלוק של A את שאר האינפורמציה של B . וככה לא משלמים על מה שלא משתמשים ועקרונות C++ נשמרים.
מה שכן באמת הcasting קצת יותר מסובך....
שיתוף:
| עוד