פולימורפיזם (מאנגלית Polymorphism, בעברית: רב־צורתיות) הוא תכונה בשפות תכנות שמאפשרת לקוד לפעול בצורה שונה לפי הטיפוס עליו הוא עובד. "טיפוס" הוא סוג נתון, למשל מספר שלם או מחרוזת. בעזרת פולימורפיזם אפשר לכתוב קוד כללי פעם אחת, והוא יקבל משמעויות שונות בהקשרים שונים.
הרעיון הוא שניתן לכתוב אלגוריתם כללי, למשל מיון מערך, בלי לדעת כל פרט על הטיפוס של איברי המערך. מספיק לדעת מה צריך: גודל המערך, איך משווים בין איברים, ואיך מחליפים סדר. בשפות עם טיפוסיות חזקה וסטטית יש צורך בכלי שנותן טיפוס גנרי (כללי) שכולל רק את הדרישות החיוניות של האלגוריתם. שפות שונות תומכות בפולימורפיזם בדרכים שונות: זיהוי טיפוסים אוטומטי (type inference), ירושה ודריסה (override) באובייקטים, או תכנות גנרי.
העמסה היא מקרה פשוט של פולימורפיזם. לדוגמה, אופרטור החיבור + עובד על מספרים שלמים ועל מספרים ממשיים. המתכנת לא צריך לדעת איך זה מתבצע בפירוט; זה שקוף ונוח.
המרה אוטומטית היא עוד צורה של אד-הוק. בשפת C, למשל, יש המרה אוטומטית של מצביעים ל-void* ולהפך. טכניקה כזו מאפשרת פונקציות גנריות מאוד, אך דורשת מהמתכנת מידע מפורש על גודל ומבנה הנתונים.
פולימורפיזם פרמטרי מאפשר לכתוב פונקציות וגיאנריות (כלליות) שפועלות על כל טיפוס שעומד בדרישות מסוימות. בשפת ++C זה מיושם עם תבניות (templates). לדוגמה תבנית max
יוצרת משפחת פונקציות שמקבלות שני ערכים מטיפוס כלשהו ומחזירות את הגדול מביניהם. המהדר ייצור מופע של הפונקציה לטיפוס שנקרא.
ב-C ניתן להשתמש במאקרואים ובממירי מצביעים כדי לדמות גנריות, אך זה חסר בדיקות טיפוסים ועלול ליצור תופעות לא צפויות.
בתבניות של ++C הגנריות מיושמות בזמן הידור (compile time). ספריית התבניות הסטנדרטית היא דוגמה לתכנות גנרי המבוסס על פולימורפיזם פרמטרי.
שפות כמו ML ו-Haskell תומכות בפולימורפיזם פרמטרי עם הסקה אוטומטית של טיפוסים (type inference). המתכנת כותב פונקציה בלי להצהיר על טיפוס; המהדר מסיק אילו טיפוסים אפשר להעביר אליה. כך נוצרת פונקציה שהיא באמת "כללית" לכל טיפוס תואם.
בג'אווה יש גנריות שמבדקים אותה בזמן קומפילציה. המידע על הטיפוסים אינו זמין בזמן ריצה, ולכן חלק מההתנהגות מוגבלת.
גם ב-C# יש מתודות גנריות שמיישמות רעיונות דומים.
פולימורפיזם של תת-טיפוסים משתמש ברעיונות של הירושה: מגדירים מושג כללי ומפיקים ממנו תת־טיפוסים ספציפיים. כך אפשר לכתוב קוד שמתייחס למושג הכללי ומפעל על מגוון רחב של מקרים. לדוגמה, ניתן להגדיר מחלקה כללית "מנוע" ואז לממש ממנה מנועים ספציפיים למכוניות, טנקים או סירות.
מנגנונים נפוצים כוללים ירושה ודריסה, תבניות (Templates), הסקה אוטומטית של טיפוסים וממשקים/abstract classes.
דוגמה יומיומית: אלגוריתם להחלפת גלגל שכתוב באופן כללי מתאים לכל סוג רכב. כל שלב יתבצע אחרת ברכב שונה, אך האלגוריתם נשאר אחד.
דוגמה מתמטית: תהליך גרם שמידט לבניית בסיס אורתונורמלי עובד בגלל הדרישות המינימליות על וקטורים ומכפלה פנימית, ולכן הוא תקף במצבים שונים.
פולימורפיזם יכול להיות ממומש בזמן ריצה (runtime) או בזמן הידור. בדוגמת ++C, פולימורפיזם של זמן ריצה מתבצע באמצעות מצביע מופשט שמצביע לאובייקט קונקרטי. פונקציה כמו changeWheel מקבלת מצביע ל-Car כללי, ומפעילה פעולות שמיושמות באופן שונה במכוניות הספציפיות.
כאשר לא ידוע בזמן הידור איזו פונקציה לקרוא, ההחלטה מתקבלת בזמן ריצה. למען כך המהדר מארגן קריאה לפונקציה על ידי מצביעים לפונקציות או מבנה שמאחסן את הממשקים המתאימים.
מימוש נפוץ הוא שימוש ב-virtual table (טבלת־ווירטואליות). לכל אובייקט יש מצביע לטבלה כזו. זה מוסיף צריכת זיכרון קטנה לכל אובייקט ולעיתים מעבר אחד בזמן הריצה כדי לקרוא לפונקציה. לרוב העלות קטנה, אך יכולה להיות משמעותית כשקריאות קצרות מאוד נעשות פעמים רבות.
בסיכום קצר: פולימורפיזם מאפשר כתיבת קוד כללי וגמיש. הוא קיים בצורות שונות, העמסה, המרה, גנריות פרמטרית וירושה, וכל שפה מממשת אותו בדרכים שונות.
פולימורפיזם (רב־צורתיות) הוא רעיון בתכנות. זה מאפשר לקוד להתנהג אחרת לפי "טיפוס". טיפוס הוא סוג של נתון, כמו מספר או מילה.
אפשר לכתוב הוראות כלליות שפועלות על הרבה סוגי דברים. למשל אלגוריתם למיון. האלגוריתם לא צריך לדעת כל פרט על סוג האיברים, רק איך להשוות ולהחליף ביניהם.
העמסה פירושה שלאותו שם יש כמה משמעויות. לדוגמה + עובד על מספרים שלמים ועל מספרים עם נקודה.
המרה היא המחשב שמשנה טיפוס אחד לאחר באופן אוטומטי. בשפת C יש המרות כאלה, אך הן דורשות זהירות.
זה כאשר כותבים פונקציה כללית שמתאימה להרבה טיפוסים. ב-++C זה נעשה בעזרת תבניות. ב-ML המהדר יודע לבד איזה טיפוס אפשר להעביר.
שפות כמו C, ++C, ML, Haskell, Java ו-C# תומכות בצורות שונות של פולימורפיזם.
רעיון של ירושה אומר שמחלקה כללית יכולה לייצג דברים דומים. למשל "מנוע" יכול לכלול מנוע של מכונית ושל סירה. הקוד מדבר על המושג הכללי, וכל סוג מבצע את הדברים שלו.
החלפת גלגל היא דוגמה: ההוראות הכלליות נכונות לכל רכב. בכל רכב הפעולות יתבצעו בצורה שונה אבל לפי אותם שלבים.
פולימורפיזם יכול לפעול בזמן הידור (כשמכינים את התוכנית) או בזמן ריצה (כשהתוכנית פועלת). מימוש נפוץ בזמן ריצה משתמש ב-virtual table. זו טבלה שמקשרת שם הפעולה לקוד המתאים לכל סוג. יש לזה מעט עלות בזיכרון ובביצועים, אבל בדרך כלל זה קטן.
פולימורפיזם עוזר לכתוב קוד קצר ונקי שיכול לעבוד על הרבה מקרים שונים.
תגובות גולשים