ݺߣ

ݺߣShare a Scribd company logo
‫פולימורפיזם – "‪Using "Virtual" and "Pure Virtual‬‬

                                                                                   ‫‪Virtual Functions‬‬
‫כבר הזכרנו שהרעיון הוא להפוך את הקוד לפולימורפי ככל שניתן ועל כן, יש מקום לדבר על האפשרות ליצור‬
                      ‫מצביע יחיד שישמש אותנו גם עבור המחלקה עצמה וגם עבור תתי המחלקות שלה.‬
  ‫היות ותת המחלקה היא נגזרת של המחלקה עצמה, כלומר, יש בה את כל ה – ‪ DNA‬של מחלקה ההורה ויותר‬
 ‫מכך, אין מניעה לפנות אליה באמצעות אותו המצביע שהיה משמש אותנו אילו רצינו לפנות למחלקת ההורה,‬
  ‫עם ההגבלות הברורות כמובן, שמצביע זה ידע לגשת אך ורק ל ‪ members‬שמוכרים לו מהמבנה של מחלקת‬
                                       ‫ההורה ולא לתוספות / שינויים אלו ואחרים שקרו אולי במחלקת הילד.‬
 ‫בחזרה לדוגמה שלנו; נניח ויצרנו פונקציה ‪ WhoRU‬חיצונית למחלקה ‪ ,Robot‬אשר מקבלת כתובת לאינסטנס‬
  ‫של רובוט, כלומר לאובייקט מסוג רובוט, ותפקידה הוא להפעיל את הפונקציה;) (‪ WhatAreYou‬עבור אותו‬
                                                                                           ‫האינסטנס.‬
                                                              ‫הצהרה ומימוש של פונקציה שכזו ייראו כך:‬
‫{ ) ‪void WhoRU ( Robot& Bot‬‬
‫} ;) (‪Bot.WhoAreYou‬‬
                                                                  ‫וקריאה לפונקציה תיעשה באופן הבא:‬
‫;)1‪WhoRU (robot‬‬
‫;)2‪WhoRU (robot‬‬
‫;)3‪WhoRU (robot‬‬
    ‫נשים לב שאנחנו שולחים לפונקציה בכל פעם אינסטנס מתת מחלקה שונה, בפעם הראשונה, אינסטנס של‬
 ‫מחלקת האב ‪ ,Robot‬בפעם השנייה אינסטנס של מחלקת הילד 2‪ R2D‬ובפעם השלישית אינסטנס של מחלקת‬
        ‫הילד ‪ ,Optimus‬אך יחד עם זאת, הפונקציה שמקבלת את הכתובת, הוגדרה לקבל כתובת אינסטנס של‬
                                                                                 ‫מחלקת האב ‪!Robot‬‬
‫במצב זה, הקומפלייר לא יודע שאנחנו מעוניינים לפנות לפונקציות שהוגדרו בתתי המחלקה ולכן הפלטים יהיו‬
                                                                        ‫זהים וילקחו ממחלקת האב.‬
    ‫על מנת לפתור סוגיה זו, עלינו לומר לקומפלייר שאנו דורשים התייחסות דווקא לפונקציה של הילד במידה‬
  ‫והיא בעלת אותה הצהרה, ואנו יכולים לעשות זאת על ידי הוספת המילה‪ virtual‬בראשית הצהרת הפונקציה‬
             ‫במחלקת האב, כך שפונקציה זו תהפוך וירטואלית אם ליורש הוגדרה פונקציה בעלת הצהרה זהה.‬
       ‫כלומר, בעת הגדרת המחלקה ‪ ,Robot‬או כאשר מתעורר הצורך בהורשה מסוג שכזה, אנו ניגש להצהרת‬
                                 ‫הפונקציה במחלקת האב ונדאג להוסיף לה את המילה השמורה ‪ virtual‬כך:‬
‫{ ‪class Robot‬‬
‫:‪public‬‬
          ‫;) (‪virtual void WhoAreYou‬‬
‫;} ... :‪private‬‬
‫‪PureVirtual-Abstract Functions‬‬
             ‫ע" מ להבין את המושג פונקציות אבסטרקטיות או פונקציות וירטואליות טהורות כמו שניתן לכנותן,‬
                                                                    ‫ראשית נסביר את המושג אבסטרקט.‬

                                                            ‫אם נשאל את ד"ר גוגל, נקבל תשובה די נכונה:‬

‫/‪ab·stract/abˈstrakt‬‬              ‫‪Existing in thought or as an idea but not having a physical or‬‬
‫:‪Adjective‬‬                        ‫.‪concrete existence‬‬

                     ‫כלומר, מדובר בפונקציות אשר מהוות קונספט רעיוני כבור פונקציות שעתידות להיגזר מהן.‬
                    ‫ע"מ להבהיר את הערפול סביב הנושא, ניקח דוגמה, איך אם לא, מהחיים האמיתיים: בן אדם.‬
     ‫בן אדם הוא קונספט רעיוני, שהרי אף אחד מאיתנו לא באמת פגש פעם בבן אדם. כן, פגשנו את יוסי, שהוא‬
     ‫גבר כבן 03 מלוס אנג'לס, פגשנו גם את רינה, בחורה בת 62 מכפר סבא... אבל הישות הזאת, "בן אדם", היא‬
                                                                ‫לא משהו שקיים באמת כישות בפני עצמה.‬
                                                        ‫אם כן, נוכל לומר ש"בן אדם" הוא טיפוס אבסטרקטי.‬
                ‫כאשר אנו מאפיינים מחלקה, כאמור, אנו חושבים על כל האפשרויות העתידיות עבור מחלקה זו.‬
       ‫אם נחזור לדוגמה שלנו, אותה פיתחנו במאמרים הקודמים בנושא, מחלקת ‪ ,Robot‬ניזכר שהיא מכילה את‬
                                                                                    ‫המתודה ‪.SetName‬‬
     ‫היות ואנו עובדים בחברה מאוד רצינית לייצור רובוטים, אנו יכולים לייצר63 סוגים שונים של רובוט ועל כן,‬
               ‫למחלקה ‪ 36 ,Robot‬מחלקות יורשות, כ" א מהן מאופיינת בהתאם לסוג הרובוט אותו היא מייצגת.‬
        ‫מכאן, שאין באמת דבר כזה "רובוט". המכונה לא מבינה מה אומרים לה אם מבקשים ממנה "רובוט", היא‬
                                                                      ‫מבינה "2‪ ,"Optimus" ,"R2D‬וכד'...‬
     ‫מכאן, ש"רובוט" הוא טיפוס אבסטרקטי. מה הופך אותו לכזה כבר ברור, אבל מה לעשות, צריך לחזור לעולם‬
                                  ‫הקוד ולשאול, כיצד אנו ממשים את ההבנה שהשגנו כאן ברמת הסינטקס?‬
         ‫ובכן, פונקציות שכאלו, כגון ‪ SetName‬למשל, אשר הנן חסרות משמעות פיסית עבור מחלקת האב, אך‬
     ‫חיוניות עבור המחלקות היורשות, ניתנות להגדרה כפונקציות‪ , pure virtual‬כלומר, פונקציות שאנו מצהירים‬
       ‫מראש ב ‪ Base Class‬שהן חלק אינטגרלי ב ‪ , Derived Class‬אך לא קיימות בפועל ב ‪ Base Class‬עצמו.‬
                               ‫בפועל, הגדרה של פונקציה כ ‪ Pure Virtual‬תיעשה באופן הבא במחלקת האב:‬
‫{ ‪class Robot‬‬
‫:‪public‬‬
           ‫; 0 = ) (‪virtual void SetName‬‬
‫... :‪private‬‬
‫;}‬
                                                                 ‫בעוד הגדרת מחלקת הילד תתבצע כרגיל:‬
‫;{ { ‪class R2D2 : public Robot‬‬
          ‫אך פרט שחשוב לציין הוא, שאין אפשרות לייצר אינסטנס של2‪ R2D‬לפני שבוצע מימוש של הפונקציה‬
     ‫‪ .SetName‬כלומר, 2‪ R2D‬בעצמו הוא אבסטרקטי, עד שמבצעים מימוש של הפונקציה ה‪ Pure Virtual‬שירש‬
                                                                                              ‫מ‪!Robot‬‬

More Related Content

בדרך לפולימורפיזם - Using Virtual/Pure Virtual

  • 1. ‫פולימורפיזם – "‪Using "Virtual" and "Pure Virtual‬‬ ‫‪Virtual Functions‬‬ ‫כבר הזכרנו שהרעיון הוא להפוך את הקוד לפולימורפי ככל שניתן ועל כן, יש מקום לדבר על האפשרות ליצור‬ ‫מצביע יחיד שישמש אותנו גם עבור המחלקה עצמה וגם עבור תתי המחלקות שלה.‬ ‫היות ותת המחלקה היא נגזרת של המחלקה עצמה, כלומר, יש בה את כל ה – ‪ DNA‬של מחלקה ההורה ויותר‬ ‫מכך, אין מניעה לפנות אליה באמצעות אותו המצביע שהיה משמש אותנו אילו רצינו לפנות למחלקת ההורה,‬ ‫עם ההגבלות הברורות כמובן, שמצביע זה ידע לגשת אך ורק ל ‪ members‬שמוכרים לו מהמבנה של מחלקת‬ ‫ההורה ולא לתוספות / שינויים אלו ואחרים שקרו אולי במחלקת הילד.‬ ‫בחזרה לדוגמה שלנו; נניח ויצרנו פונקציה ‪ WhoRU‬חיצונית למחלקה ‪ ,Robot‬אשר מקבלת כתובת לאינסטנס‬ ‫של רובוט, כלומר לאובייקט מסוג רובוט, ותפקידה הוא להפעיל את הפונקציה;) (‪ WhatAreYou‬עבור אותו‬ ‫האינסטנס.‬ ‫הצהרה ומימוש של פונקציה שכזו ייראו כך:‬ ‫{ ) ‪void WhoRU ( Robot& Bot‬‬ ‫} ;) (‪Bot.WhoAreYou‬‬ ‫וקריאה לפונקציה תיעשה באופן הבא:‬ ‫;)1‪WhoRU (robot‬‬ ‫;)2‪WhoRU (robot‬‬ ‫;)3‪WhoRU (robot‬‬ ‫נשים לב שאנחנו שולחים לפונקציה בכל פעם אינסטנס מתת מחלקה שונה, בפעם הראשונה, אינסטנס של‬ ‫מחלקת האב ‪ ,Robot‬בפעם השנייה אינסטנס של מחלקת הילד 2‪ R2D‬ובפעם השלישית אינסטנס של מחלקת‬ ‫הילד ‪ ,Optimus‬אך יחד עם זאת, הפונקציה שמקבלת את הכתובת, הוגדרה לקבל כתובת אינסטנס של‬ ‫מחלקת האב ‪!Robot‬‬ ‫במצב זה, הקומפלייר לא יודע שאנחנו מעוניינים לפנות לפונקציות שהוגדרו בתתי המחלקה ולכן הפלטים יהיו‬ ‫זהים וילקחו ממחלקת האב.‬ ‫על מנת לפתור סוגיה זו, עלינו לומר לקומפלייר שאנו דורשים התייחסות דווקא לפונקציה של הילד במידה‬ ‫והיא בעלת אותה הצהרה, ואנו יכולים לעשות זאת על ידי הוספת המילה‪ virtual‬בראשית הצהרת הפונקציה‬ ‫במחלקת האב, כך שפונקציה זו תהפוך וירטואלית אם ליורש הוגדרה פונקציה בעלת הצהרה זהה.‬ ‫כלומר, בעת הגדרת המחלקה ‪ ,Robot‬או כאשר מתעורר הצורך בהורשה מסוג שכזה, אנו ניגש להצהרת‬ ‫הפונקציה במחלקת האב ונדאג להוסיף לה את המילה השמורה ‪ virtual‬כך:‬ ‫{ ‪class Robot‬‬ ‫:‪public‬‬ ‫;) (‪virtual void WhoAreYou‬‬ ‫;} ... :‪private‬‬
  • 2. ‫‪PureVirtual-Abstract Functions‬‬ ‫ע" מ להבין את המושג פונקציות אבסטרקטיות או פונקציות וירטואליות טהורות כמו שניתן לכנותן,‬ ‫ראשית נסביר את המושג אבסטרקט.‬ ‫אם נשאל את ד"ר גוגל, נקבל תשובה די נכונה:‬ ‫/‪ab·stract/abˈstrakt‬‬ ‫‪Existing in thought or as an idea but not having a physical or‬‬ ‫:‪Adjective‬‬ ‫.‪concrete existence‬‬ ‫כלומר, מדובר בפונקציות אשר מהוות קונספט רעיוני כבור פונקציות שעתידות להיגזר מהן.‬ ‫ע"מ להבהיר את הערפול סביב הנושא, ניקח דוגמה, איך אם לא, מהחיים האמיתיים: בן אדם.‬ ‫בן אדם הוא קונספט רעיוני, שהרי אף אחד מאיתנו לא באמת פגש פעם בבן אדם. כן, פגשנו את יוסי, שהוא‬ ‫גבר כבן 03 מלוס אנג'לס, פגשנו גם את רינה, בחורה בת 62 מכפר סבא... אבל הישות הזאת, "בן אדם", היא‬ ‫לא משהו שקיים באמת כישות בפני עצמה.‬ ‫אם כן, נוכל לומר ש"בן אדם" הוא טיפוס אבסטרקטי.‬ ‫כאשר אנו מאפיינים מחלקה, כאמור, אנו חושבים על כל האפשרויות העתידיות עבור מחלקה זו.‬ ‫אם נחזור לדוגמה שלנו, אותה פיתחנו במאמרים הקודמים בנושא, מחלקת ‪ ,Robot‬ניזכר שהיא מכילה את‬ ‫המתודה ‪.SetName‬‬ ‫היות ואנו עובדים בחברה מאוד רצינית לייצור רובוטים, אנו יכולים לייצר63 סוגים שונים של רובוט ועל כן,‬ ‫למחלקה ‪ 36 ,Robot‬מחלקות יורשות, כ" א מהן מאופיינת בהתאם לסוג הרובוט אותו היא מייצגת.‬ ‫מכאן, שאין באמת דבר כזה "רובוט". המכונה לא מבינה מה אומרים לה אם מבקשים ממנה "רובוט", היא‬ ‫מבינה "2‪ ,"Optimus" ,"R2D‬וכד'...‬ ‫מכאן, ש"רובוט" הוא טיפוס אבסטרקטי. מה הופך אותו לכזה כבר ברור, אבל מה לעשות, צריך לחזור לעולם‬ ‫הקוד ולשאול, כיצד אנו ממשים את ההבנה שהשגנו כאן ברמת הסינטקס?‬ ‫ובכן, פונקציות שכאלו, כגון ‪ SetName‬למשל, אשר הנן חסרות משמעות פיסית עבור מחלקת האב, אך‬ ‫חיוניות עבור המחלקות היורשות, ניתנות להגדרה כפונקציות‪ , pure virtual‬כלומר, פונקציות שאנו מצהירים‬ ‫מראש ב ‪ Base Class‬שהן חלק אינטגרלי ב ‪ , Derived Class‬אך לא קיימות בפועל ב ‪ Base Class‬עצמו.‬ ‫בפועל, הגדרה של פונקציה כ ‪ Pure Virtual‬תיעשה באופן הבא במחלקת האב:‬ ‫{ ‪class Robot‬‬ ‫:‪public‬‬ ‫; 0 = ) (‪virtual void SetName‬‬ ‫... :‪private‬‬ ‫;}‬ ‫בעוד הגדרת מחלקת הילד תתבצע כרגיל:‬ ‫;{ { ‪class R2D2 : public Robot‬‬ ‫אך פרט שחשוב לציין הוא, שאין אפשרות לייצר אינסטנס של2‪ R2D‬לפני שבוצע מימוש של הפונקציה‬ ‫‪ .SetName‬כלומר, 2‪ R2D‬בעצמו הוא אבסטרקטי, עד שמבצעים מימוש של הפונקציה ה‪ Pure Virtual‬שירש‬ ‫מ‪!Robot‬‬