מאמר שלישי בסדרת מאמרים בנושא תכנות מונחה עצמים, והפעם - העמסת ועקיפת פונקציות
Convert to study guideBETA
Transform any presentation into a summarized study guide, highlighting the most important points and key insights.
1 of 3
Download to read offline
More Related Content
בדרך לפולימורפיזם - העמסת ועקיפת פונקציות
1. בדרך לפולימורפיזם – העמסת ועקיפת פונקציות
בעולם התוכן של תכנות מונחה עצמים ושל כתיבת קוד בכלל קיימת שאיפה תמידית לכתוב קוד כמה שיותר
פולימורפי – ג' נרי כך שנוכל להשתמש ביעילות ובחסכוניות באותן שורות קוד לביצוע פעולות בעלות אופי
דומה, על פני שימוש חוזר, שכפול קוד והזזה של נתונים ממקום למקום שלא לצורך.
פולימורפיזם, משמעותו, מצב בו קיימות מספר פונקציות שעל אף העובדה שהן חולקות את אותו השם,
הן מבצעות פעולות שונות.
ראשית, נעסוק בהבדלים בין העמסת פונקציות לעקיפת פונקציות בדרך לכתיבת קוד פולימורפי יותר.
הגורם העיקרי המבדיל בין "העמסת" ל"עקיפת" פונקציות הוא מיקומן בהיררכיה המחלקתית.
כפי שנהוג לציין בספרות, "העמסת פונקציה" נעשית בצורה אופקית, כלומר הקשר הוא בין פונקציות בעלות
אותו שם הנמצאות באותה דרגה של הורשה בהיררכיה המחלקתית, כאשר ההבדל היחיד בינהן הוא מספר
ו/או סוג הפרמטרים שהן מקבלות, בעוד "עקיפת פונקציה" נעשית בצורה אנכית, כלומר הקשר הוא בין
פונקציות זהות לחלוטין הנמצאות ברמות שונות בהיררכיה המחלקתית, קרי, פועלות בקשר שבין
ה – base classל – ,derived classאו אם תרצו, הקשר שבין האבא והבן ( או הבת :-) ).
העמסת פונקציות
היתרון הבולט ביותר בהעמסת פונקציות הוא היכולת להשתמש "באותה פונקציה" בדרכים שונות.
נראה דוגמה:
נניח וקיימת מחלקה בשם Robotובמחלקה זו העמסנו את הפונקציה SetDataבאופן כזה שהיא יכולה לקבל
פרמטר אחד, שני פרמטרים או לא לקבל פרמטרים בכלל:
} ;void SetData( ) { cout << "You have not set any data..." << endl
} ;void SetData ( int x ) { cout << "Data Recorded: " << x << endl
} ;void SetData ( int x, int y ) { cout << "Data Recorded: " << x << " " << y << endl
ונניח וקיים הרובוט 2 ,R2Dאז נוכל לבצע הקריאות:
;) (R2D2.SetData
;)5(R2D2.SetData
;)9,7(R2D2.SetData
ולצפות לפלט הבא:
...You have not set any data
5 :Data Recorded
9 7 :Data Recorded
2. ברצוני להציג דוגמה עקיפה לעניין זה. סוג של אנקדוטה קטנה, שאני מרגיש שיש צורך לעמוד על קיומה.
נניח ו SetDataהוא קונסטרקטור אשר ברצוננו "להעמיס" (שימו לב. אני בכוונה מציין את המרכאות על
המושג להעמיס), כך שיקבל 2 פרמטרים, פרמטר יחיד או לא יקבל פרמטרים בכלל, אך בהיעדר הזנת אחד או
יותר מהערכים, אנו נשתמש בערכי ברירת מחדל שהוגדרו מראש.
ההצהרה על הקונסטרקטור תיעשה באופן הבא:
;) 0=void SetData ( int=0, int=0, int
ומימוש שלו ייראה כך:
;} ... { ) void SetData ( int x, int y, int z
אם כן, לא באמת ביצענו העמסת פונקציה במקרה זה, הרי שיש לנו הצהרה אחת, ומימוש אחד עבור
הקונסטרקטור שבדוגמה ואמרנו קודם, שבהעמסה, אנו נממש את הפונקציה מס' פעמים עם זהות בשם
הפונקציה ושוני במספר הפרמטרים או סוגם.
הסיבה שבגינה ציינתי דוגמה זו, היא צד המשתמש.
עבור המשתמש, מדובר לכאורה בפונקציה שהועמסה, שהרי הוא יכול לקרוא לה עם שני פרמטרים, פרמטר
בודד או ללא פרמטרים כלל. מעניין, נכון?
3. עקיפת פונקציות
עבור עקיפת פונקציות, נציין את הגישה הישירה לביצוע העקיפה, ובמימושים מתקדמים יותר, נעסוק בהמשך.
היתרון העיקרי בעקיפת פונקציות הוא היכולת "להגדיר מחדש" פונקציה שעברה בירושה מה– Base Class
כך שתישאר בעלת אותו השם ואותן התכונות, אך תבצע פעולה מותאמת אישית עבור היורש.
נוכל לראות זאת בדוגמה הבאה:
נניח וקיימת מחלקה בשם Robotולה תתי מחלקות בשמות 2 R2Dו .Optimus
כשמריצים את הפונקציה ;) ( WhatAreYouעל הרובוט ב- Base Classהוא עונה "אני רובוט אב", ומכאן שגם
הבנים שלו ירשו את היכולת לענות תשובה זו, אך ברור לכל שהתשובה "אני רובוט בן" היא הנכונה עבורו.
כמובן שיכולנו ליצור פונקציה נוספת בשם ;) (2 WhatAreYouלמשל, בה יוכל הבן לומר מי הוא באמת, אך
ברצוננו לשמור על המבנה הנוכחי מבלי להוסיף פונקציות מיותרות שרק יעמיסו על הקוד ועלולות לגרום
לבלבול עקב האפשרות של הבן "לשקר" ולומר שהוא אב...
על כן, עלינו לבצע "עקיפת פונקציה" על מנת להתאים אותה לצרכי הבן. אנו נבצע זאת על ידי שימוש בהגדרת
פונקציה הזהה לחלוטין לזו של האב (הדבר אפשרי היות והפונקציות נמצאות ברמות היררכיה שונות), ובכך
"לדרוס" את פונקצית האב באופן הבא:
{ class Robot
}} ;void WhatAreYou( ) { cout << "I'm Robot, The father of all robots" << endl
{ class R2D2: public Robot
}} ;void WhatAreYou( ) { cout << "I'm R2D2, The child of class Robot!" << endl
{ class Optimus: public Robot
}} ;void WhatAreYou( ) { cout << "I'm Optimus, The child of class Robot!" << endl
ובהנחה וקיימים הרובוטים ;1 ,Optimus robot3;, R2D2 robot2;, Robot robotנוכל לבצע את הקריאות
הבאות:
;) (robot1.WhatAreYou
;) (robot2.WhatAreYou
;) (robot3.WhatAreYou
ולצפות לפלט הבא:
!I'm Robot, The father of all robots
!I'm R2D2, The child of class Robot
!I'm Optimus, The child of class Robot