1 / 19

תכנות מונחה עצמים והנדסת תוכנה – תשע"ד

תכנות מונחה עצמים והנדסת תוכנה – תשע"ד. פולימורפיזם ( Polymorphism ). 1. מבוא. פולימורפיזם (רב צורתיות) הוא מנגנון מרכזי בתכנות מונחה עצמים. המנגנון מאפשר לממש מבני נתונים ואלגוריתמים גנריים. דוגמאות: מבנה נתונים אחד שמכיל צורות שונות (מעגל, מלבן, קטע, משולש,...).

saima
Télécharger la présentation

תכנות מונחה עצמים והנדסת תוכנה – תשע"ד

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. תכנות מונחה עצמים והנדסת תוכנה – תשע"ד פולימורפיזם (Polymorphism) 1

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

  3. מימוש פונקציה מחדש • ראינו שבירושה אפשר לממש פונקציות מחדש: class A { : void print() { cout << “A–print”; } }; class B : public A { : void print() { cout << “B–print”; } }; int main() { A a; B b; a.print(); // A-print b.print(); // B-print }

  4. המרה בירושה • עצם b הוא סוג של a, לכן ההמרה הבאה תקינה: a = b; // the A part of b is assigned a.print(); // A-print • אותן המרות יתבצעו עבור מצביעים: A* aPtr = &a; B* bPtr = &b; aPtr->print(); // A-print bPtr->print(); // B-print aPtr = (A*)&b; // direct conversion from B* to A* aPtr = &b // same as before aPtr->print(); // A-print • דוגמא 13_5

  5. המרה בירושה (המשך) • ההמרה ההפוכה אינה תקינה: b = a; // error (A is not kind of B) bPtr = &a; // the same error • דוגמא 13_6 • בפרט, אחרי המרה מ-B ל-A כבר לא ניתן לגשת לחלקים של B: aPtr = &b; aPtr->bFunction(); // error • דוגמא 13_7

  6. המרה בירושה (המשך) aPtr = &b; aPtr->print(); // A-print • מופעלת הפונקציה של A. • aPtr מצביע על עצם של B (על החלק ה-A של b). כל המידע על העצם b נמצא במקום זה בזיכרון. • מבחינה טכנית יכולנו להפעיל פונקציות של B באמצעות aPtr.

  7. פונקציה וירטואלית (virtual) • פונקציה וירטואלית תאפשר לגשת לפונקציות של B באמצעות aPtr: class A { : virtual void print(); }; class B : public A { : virtual void print(); // writing “virtual” here is optional };

  8. פונקציה וירטואלית (המשך) int main() { : aPtr->print(); // A-print bPtr->print(); // B-print aPtr = &b; aPtr->print(); // B-print } • aPtr מתייחס לחלק ה-A של עצם של B. • באמצעות המצביע aPtr אפשר להפעיל פונקציה של B. • נקרא פולימורפיזם. • דוגמא 13_8_10

  9. מנגנון הפולימורפיזם • לשם מה נזדקק למנגנון הפולימורפיזם? Base* basePtr; Derived1 d1; Derived2 d2; Derived3 d3; ,… basePtr = &d1; or basePtr = &d2; or basePtr = &d1; ,… basePtr->print(); // same code for activating different functions Base virtual void print() Derived1 virtual void print() Derived2 virtual void print() Derived3 virtual void print()

  10. דוגמאות לשימוש בפולימורפיזם • מבנה נתונים כללי: מערך של צורות שונות והציור שלהן. • אלגוריתם כללי: חישוב המקסימום הנומרי של פונקציות. • אלגוריתם כללי: החלפת גלגל בכלי תחבורה כללי. • מבנה נתונים כללי: רשימה משורשרת של צורות שונות.

  11. חזרה על הנקודות המרכזיות • הפעלת פונקציה וירטואלית בעזרת ערך: A a; B b; a.print(); // A-print a = b; a.print(); // A-print • הפעלה פונקציה וירטואלית בעזרת מצביע: A* aPtr; aPtr = &a; aPtr->print(); // A-print aPtr = &b; aPtr->print(); // B-print

  12. חזרה על הנקודות המרכזיות (המשך) • הפעלה פונקציה וירטואלית בעזרת הפניה (דומה למצביע): A& aRef1 = a; aRef1.print(); // A-print A& aRef2 = b; aRef2.print(); // B-print

  13. חזרה על הנקודות המרכזיות (המשך) • המרות לא חוקיות: b = a; // error bPtr = &a; // error bRef = a; // error • חוסר גישה: aPtr = &b; aPtr->bFunction(); // error • אם C יורשת מ-A ולא מממשת מחדש את הפונקציה print() (וירטואלית או לא), אז הקריאה אליה מתייחסת למימוש שהוגדר ב-A : aPtr = &c; aPtr->print(); // A-print

  14. פונקציה הורסת וירטואלית • אובייקט של מחלקה יורשת עלול להשתחרר באופן חלקי בלבד במקרה הבא: class A { public: ~A() { cout << “A-dtor”; } }; class B : public A { public: B() : _p( new int(7) ) {} ~B() { cout << “B-dtor”; delete _p; } private: int* _p; };

  15. פונקציה הורסת וירטואלית (המשך) int main() { A* aPtr = new B(); delete aPtr; } • מהלך התוכנית: יודפס A-dtor, וההקצאה ע"י _p לא תשוחרר. • פתרון: להגדיר את הפונקציה ההורסת של A כפונקציה וירטואלית. • פלט תקין: B-dtor, A-dtor (מימין לשמאל).

  16. פונקציה הורסת וירטואלית (המשך) • פונקציות בונות ופונקציות השמה (set) לא יוגדרו כוירטואליות (עבור פונקציות בונות תתקבל שגיאת קומפילציה). • מומלץ להגדיר פונקציה הורסת וירטואלית במחלקת הבסיס גם במקרה שהיא אינה עושה דבר. הפונקציות ההורסות של המחלקות היורשות יבצעו שחרור זיכרון מלא.

  17. מחלקה אבסטרקטית • לעיתים נרצה להגדיר מחלקות מופשטות לחלוטין שתפקידן להוות מכנה משותף למחלקות אחרות. • יצירת עצמים ממחלקה כזו היא חסרת משמעות. • מחלקה כזו תקרא מחלקה מורישה אבסטרקטית (abstract base class). • דוגמא: מחלקת Shape מהווה מכנה משותף למרובע, משולש, עיגול וכדומה. הגדרת עצם ממחלקה זו היא חסרת משמעות. ציור עצם ממחלקה זו היא פעולה חסרת משמעות.

  18. מחלקה אבסטרקטית (המשך) • מחלקה תוגדר להיות אבסטרקטית אם לפחות אחת הפונקציות בה היא וירטואלית טהורה. • פונקציה וירטואלית טהורה היא פונקציה ללא מימוש במחלקה (אלא רק במחלקות היורשות ממנה). • הגדרת פונקציה וירטואלית טהורה: class Shape { : virtual void draw()=0; }; • המחלקה Shape היא מחלקה אבסטרקטית.

  19. מחלקה אבסטרקטית (המשך) • לא ניתן להגדיר עצמים של מחלקה אבסטרקטית, אלא רק מצביע או הפניה לעצם ממחלקה אבסטרקטית. • כל מחלקה יורשת צריכה לספק מימוש לפונקציה הוירטואלית טהורה. • מה ההבדל בין פונקציה וירטואלית טהורה לבין מימוש ריק? • מחלקה יורשת שאינה מממשת פונקציה וירטואלית טהורה, הופכת אף היא למחלקה אבסטרקטית. • דוגמא לשימוש במחלקה אבסטרקטית ופונקציה וירטואלית טהורה. • דוגמא למחלקה יורשת שאינה מממשת פונקציה וירטואלית טהורה.

More Related