ݺߣ

ݺߣShare a Scribd company logo
‫מחלקות – ‪Classes‬‬

                                                           ‫אנו עוסקים בפיתוח על רעיון המבנים (‪ )Structures‬ב – ‪.C‬‬

    ‫נבחין בהגדרת משתנה מסוג ‪ int‬לדוגמה: 01=‪ ,int x‬כאן אנו עושים שימוש בטיפוס נתונים שמוגדר מראש והאובייקט‬
      ‫נבנה במחסנית, אנו נעשה הבחנה בין אובייקטים שנבנים במחסנית לבין אובייקטים שנבנים בערימה היות וקיימים‬
                                     ‫הבדלים משמעותיים הן בדרכי הגישה והן בעלות וזמני הגישה אל אובייקטים אלו.‬

                                                                                                ‫בחזרה למחלקות.‬

                                  ‫ניתן להתבונן במחלקות כבתרשים אפיון עבור אובייקטים שאנו רוצים לבנות בזיכרון.‬

 ‫בניגוד ל –‪ ... string ,double ,int‬וכד', שהם טיפוסים מוגדרים מראש, מחלקה היא טיפוס נתונים שאנו בונים בעצמנו ועל‬
                                                                     ‫כן, הוא יכיל מאפיינים ותכונות שאנו נעניק לו.‬

           ‫נניח ונרצה ליצור מחלקה של רובוטים. כאן יש מקום לדבר על המושג ‪ .Encapsulation‬הרעיון שעומד מאחורי‬
                                                       ‫אנקפסולציה הוא שילוב בין מהו האובייקט לבין מה הוא עושה.‬

    ‫לכל מחלקה יש משתנים – ‪ modifiers‬מסוגים שונים. משתנים אלו יכולים להיות ציבוריים – ‪ ,public‬פרטיים - ‪private‬‬
                                                                                                            ‫ועוד.‬

     ‫כמו כן, לכל מחלקה יש בנאי והורס. אותו הבנאי הוא פונקציה מיוחדת שנכתבה בצורה מאוד מסוימת: שם המחלקה‬
‫שאובייקטים מהסוג שלה היא בונה ללא ערך החזרה. כלומר, אם החלטנו לבנות מחלקה של רובוטים – ‪ ,Robots‬אז הבנאי‬
     ‫של המחלקה ייקרא )(‪ .Robots‬הורס של המחלקה ייקרא באופן זהה לבנאי רק עם ∾ לפני השם שלו כך: )(‪.∾Robots‬‬

‫ככל אצבע, באופן עקרוני וכללי; הבנאי, ההורס ופונקציות אחרות יהיו תחת הכותרת ‪ public‬ומשתנים יהיו תחת הכותרת‬
                              ‫:‬
                                                                                                        ‫:‪.private‬‬

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

‫{ ‪Class Robots‬‬
‫:‪Public‬‬
        ‫} ;"‪Robots () { cout << "Building a Robot‬‬
        ‫} ;"‪∾Robots () { cout << "Destroying a Robot‬‬
‫כעת, כמו שאמרנו, מחלקה היא לא אחרת מאשר סכימה של האובייקט שברצוננו ליצור ועל כן, בהמשך לדוגמה שלנו,‬
                                                         ‫נשאל את עצמנו אילו פונקציות האובייקט שלנו מבצע.‬

‫נניח והרובוט שלנו יודע לבצע 2 פעולות בלבד: לחשב ולאכול. פעולות אלו, המכונות ‪ ,Member Methods‬יהיו ציבוריות‬
                                ‫ותתאפשר אליהן גישה מחוץ למחלקה. כאן הגדרנו את מה שהאובייקט שלנו עושה.‬

‫כמובן, שאין מניעה להמשיך ולאפיין את האובייקט שלנו כאשר כל המאפיינים שלו ציבוריים, כלומר, מבחינה תחבירית,‬
‫אין שום מניעה לעשות כך, אך זהו המקום לציין שיש חשיבות גדולה לבצע את ההפרדה שהוזכרה קודם בדבר ציבוריות‬
                                                                                    ‫ופרטיות של מאפיינים.‬

                                       ‫אם בכל זאת נגדיר הכול כציבורי, אנו נפספס אלמנט חשוב ביותר– מיסוך.‬

 ‫נסביר: ++‪ C‬מאפשרת לנו להגדיר אלמנטים מסוימים כפרטיים ובכך לחסום את אפשרות הגישה הישירה אליהם מחוץ‬
  ‫למחלקה, כך שניתן יהיה לגשת אליהם אך ורק דרך פונקציות ציבוריות. כל פונקציה ציבורית תוגדר באיזה אופן היא‬
‫ניגשת לנתונים וכיצד היא משנה אותם, כך שאנו יכולים להיות סמוכים ובטוחים ש"כל צופה שילם על כרטיס כדי לצפות‬
                                                                                  ‫במופע" (בהקבלה כמובן).‬

                                         ‫כעת נדבר על הגדרת הפרטיים: כאן נגדיר את מה שהאובייקט שלנו הוא.‬

      ‫בחזרה לדוגמא שלנו, נגדיר, כי לרובוט שלנו התכונות היסודיות הבאות: שם, חוכמה והאם הוא מאושר. כל אחת‬
‫מהתכונות הללו תהא מוגנת משינוי באופן ישיר, ותתאפשר אליהן גישה אך ורק דרך פונקציות תיווך ציבוריות שיוגדרו‬
                                                                                                   ‫מראש.‬

 ‫אין משמעות לשם של פונקציות אלו, אך לשם הסדר הטוב ומתוך מוסכמה קיימת בתחום, נשתמש ברישא ‪ Set‬על מנת‬
                                             ‫לשנות ערך של משתנה וברישא ‪ Get‬על מנת לאחזר ערך של משתנה.‬

‫פונקציות אלו, המכונות ‪ ,Accessor Methods‬יוגדרו בהתאמה עבור התכונות אותן הן מגדירות או שעבורן הן מאחזרות‬
   ‫מידע, כך שבדוגמה שלנו למשל, אם המשתנה ‪ Name‬הוא מסוג ‪ ,string‬כך גם פונקציות התיווך שלו יוגדרו: על מנת‬

 ‫לאחזר את ערכו של המשתנה ‪ Name‬נבנה פונקצית תיווך שמחזירה ‪ ,string‬ועל מנת להציב ערך במשתנה ‪ Name‬נבנה‬
                      ‫פונקצית תיווך מסוג ‪ string‬המבצעת השמה. ובאופן כללי: ‪.private member = public value‬‬

   ‫נשים לב לעובדה שאת כל הפעולות על המשתנים הפרטיים אנו נאלצים לבצע על ידי פונקציות התיווך, כל עוד שאנו‬
   ‫נמצאים מחוץ לגבולות המחלקה (פונקצית ‪ main‬וכדומה), אך כל עוד שאנו נמצאים בתוך המחלקה, אין מניעה לגשת‬

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

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

         ‫‪ ... int, double‬כך שאם בדוגמא שלנו יצרנו מחלקה שנקראת ‪ ,Robot‬אז יצירת רובוט בשם 2‪ r2d‬במחסנית תהיה‬

                                                                                                 ‫;2‪.Robot r2d‬‬

                        ‫כעת, נגדיר את שם הרובוט באמצעות פונקצית התיווך ‪r2d2.SetName ("R2D2"); :SetName‬‬

                            ‫נשים לב שהגישה היא דרך האובייקט עצמו ולא דרך המחלקה (‪ r2d2.Set‬ולא ‪.)Robot.Set‬‬

                                       ‫כדי לקבל את רמת החוכמה של 2‪ , R2D‬אנו ניגש באמצעות פונקצית התיווך כך:‬

                                                                                      ‫;)(‪.r2d2.GetSmartLevel‬‬

   ‫כעת, נבנה פונקציה שמציגה לנו את מכלול הנתונים לגבי רובוט מסוים. על מנת לבצע זאת, נבחין בתכונה שציינו קודם‬
      ‫לכן: היות והפונקציה נבנית בגבולות המחלקה, אין לנו צורך בפונקציית התיווך, ואנו יכולים לגשת באופן ישיר לכל‬
 ‫משתנה פרטי כאילו היה ציבורי וכמובן שזאת מבלי לסתור את האמור עד כה, שהרי כל עוד שאנו בגבולות המחלקה, אין‬
   ‫שום מניעה מאיתנו לגשת למשתנים. המניעה באה על מנת לא לאפשר גישה שכזו מבחוץ. ועל כן, פונקציה שכזו תיראה‬
                           ‫כך: } ;‪GetToKnowRobot() { cout << Name << " " << SmartLevel << " " << IsHappy‬‬

                                                                                ‫ואז: ;)(‪r2d2.getToKnowRobot‬‬

    ‫היות ואובייקטים ממחלקות מסוימות יכולים להיות "כבדים" והזזתם ממקום למקום דרך המחסנית עלולה לעלות מחיר‬
                                           ‫כבד של פעולות מעבד וזיכרון, אנו נעדיף לבצע את העבודה דרך הערימה.‬

‫נשים לב שמדובר בעבודה עם מצביעים ולכן אנו נצטרך להיזהר ממצבים בהם האובייקט יהיה בזיכרון ויצרוך משאבים, אך‬
                                                                                           ‫אנו נאבד גישה אליו.‬

              ‫ביצירת אובייקט בערימה, אנו נרגיש בשני שינויים עיקריים בהתנהלות שלנו: היצירה תתבצע באופן הבא:‬

‫;)( ‪Robot * OptimusPrime = new Robot‬‬
  ‫;)"‪OptimusPrime -> SetName("Optimus Prime‬‬                                   ‫והגישה אליו תתבצע באופן הבא:‬

More Related Content

תכנות מונחה עצמים - מחלקות

  • 1. ‫מחלקות – ‪Classes‬‬ ‫אנו עוסקים בפיתוח על רעיון המבנים (‪ )Structures‬ב – ‪.C‬‬ ‫נבחין בהגדרת משתנה מסוג ‪ int‬לדוגמה: 01=‪ ,int x‬כאן אנו עושים שימוש בטיפוס נתונים שמוגדר מראש והאובייקט‬ ‫נבנה במחסנית, אנו נעשה הבחנה בין אובייקטים שנבנים במחסנית לבין אובייקטים שנבנים בערימה היות וקיימים‬ ‫הבדלים משמעותיים הן בדרכי הגישה והן בעלות וזמני הגישה אל אובייקטים אלו.‬ ‫בחזרה למחלקות.‬ ‫ניתן להתבונן במחלקות כבתרשים אפיון עבור אובייקטים שאנו רוצים לבנות בזיכרון.‬ ‫בניגוד ל –‪ ... string ,double ,int‬וכד', שהם טיפוסים מוגדרים מראש, מחלקה היא טיפוס נתונים שאנו בונים בעצמנו ועל‬ ‫כן, הוא יכיל מאפיינים ותכונות שאנו נעניק לו.‬ ‫נניח ונרצה ליצור מחלקה של רובוטים. כאן יש מקום לדבר על המושג ‪ .Encapsulation‬הרעיון שעומד מאחורי‬ ‫אנקפסולציה הוא שילוב בין מהו האובייקט לבין מה הוא עושה.‬ ‫לכל מחלקה יש משתנים – ‪ modifiers‬מסוגים שונים. משתנים אלו יכולים להיות ציבוריים – ‪ ,public‬פרטיים - ‪private‬‬ ‫ועוד.‬ ‫כמו כן, לכל מחלקה יש בנאי והורס. אותו הבנאי הוא פונקציה מיוחדת שנכתבה בצורה מאוד מסוימת: שם המחלקה‬ ‫שאובייקטים מהסוג שלה היא בונה ללא ערך החזרה. כלומר, אם החלטנו לבנות מחלקה של רובוטים – ‪ ,Robots‬אז הבנאי‬ ‫של המחלקה ייקרא )(‪ .Robots‬הורס של המחלקה ייקרא באופן זהה לבנאי רק עם ∾ לפני השם שלו כך: )(‪.∾Robots‬‬ ‫ככל אצבע, באופן עקרוני וכללי; הבנאי, ההורס ופונקציות אחרות יהיו תחת הכותרת ‪ public‬ומשתנים יהיו תחת הכותרת‬ ‫:‬ ‫:‪.private‬‬ ‫הבנאי נקרא בכל פעם שיוצרים אובייקט ממחלקה מסוימת וגם אם אינו מוגדר מראש על ידנו, ייווצר בנאי והורס‬ ‫ו‬ ‫דפולטיביים. אם נחזור למחלקת הרובוטים שלנו נוכל לסכם מה שעשינו עד כה:‬ ‫{ ‪Class Robots‬‬ ‫:‪Public‬‬ ‫} ;"‪Robots () { cout << "Building a Robot‬‬ ‫} ;"‪∾Robots () { cout << "Destroying a Robot‬‬
  • 2. ‫כעת, כמו שאמרנו, מחלקה היא לא אחרת מאשר סכימה של האובייקט שברצוננו ליצור ועל כן, בהמשך לדוגמה שלנו,‬ ‫נשאל את עצמנו אילו פונקציות האובייקט שלנו מבצע.‬ ‫נניח והרובוט שלנו יודע לבצע 2 פעולות בלבד: לחשב ולאכול. פעולות אלו, המכונות ‪ ,Member Methods‬יהיו ציבוריות‬ ‫ותתאפשר אליהן גישה מחוץ למחלקה. כאן הגדרנו את מה שהאובייקט שלנו עושה.‬ ‫כמובן, שאין מניעה להמשיך ולאפיין את האובייקט שלנו כאשר כל המאפיינים שלו ציבוריים, כלומר, מבחינה תחבירית,‬ ‫אין שום מניעה לעשות כך, אך זהו המקום לציין שיש חשיבות גדולה לבצע את ההפרדה שהוזכרה קודם בדבר ציבוריות‬ ‫ופרטיות של מאפיינים.‬ ‫אם בכל זאת נגדיר הכול כציבורי, אנו נפספס אלמנט חשוב ביותר– מיסוך.‬ ‫נסביר: ++‪ C‬מאפשרת לנו להגדיר אלמנטים מסוימים כפרטיים ובכך לחסום את אפשרות הגישה הישירה אליהם מחוץ‬ ‫למחלקה, כך שניתן יהיה לגשת אליהם אך ורק דרך פונקציות ציבוריות. כל פונקציה ציבורית תוגדר באיזה אופן היא‬ ‫ניגשת לנתונים וכיצד היא משנה אותם, כך שאנו יכולים להיות סמוכים ובטוחים ש"כל צופה שילם על כרטיס כדי לצפות‬ ‫במופע" (בהקבלה כמובן).‬ ‫כעת נדבר על הגדרת הפרטיים: כאן נגדיר את מה שהאובייקט שלנו הוא.‬ ‫בחזרה לדוגמא שלנו, נגדיר, כי לרובוט שלנו התכונות היסודיות הבאות: שם, חוכמה והאם הוא מאושר. כל אחת‬ ‫מהתכונות הללו תהא מוגנת משינוי באופן ישיר, ותתאפשר אליהן גישה אך ורק דרך פונקציות תיווך ציבוריות שיוגדרו‬ ‫מראש.‬ ‫אין משמעות לשם של פונקציות אלו, אך לשם הסדר הטוב ומתוך מוסכמה קיימת בתחום, נשתמש ברישא ‪ Set‬על מנת‬ ‫לשנות ערך של משתנה וברישא ‪ Get‬על מנת לאחזר ערך של משתנה.‬ ‫פונקציות אלו, המכונות ‪ ,Accessor Methods‬יוגדרו בהתאמה עבור התכונות אותן הן מגדירות או שעבורן הן מאחזרות‬ ‫מידע, כך שבדוגמה שלנו למשל, אם המשתנה ‪ Name‬הוא מסוג ‪ ,string‬כך גם פונקציות התיווך שלו יוגדרו: על מנת‬ ‫לאחזר את ערכו של המשתנה ‪ Name‬נבנה פונקצית תיווך שמחזירה ‪ ,string‬ועל מנת להציב ערך במשתנה ‪ Name‬נבנה‬ ‫פונקצית תיווך מסוג ‪ string‬המבצעת השמה. ובאופן כללי: ‪.private member = public value‬‬ ‫נשים לב לעובדה שאת כל הפעולות על המשתנים הפרטיים אנו נאלצים לבצע על ידי פונקציות התיווך, כל עוד שאנו‬ ‫נמצאים מחוץ לגבולות המחלקה (פונקצית ‪ main‬וכדומה), אך כל עוד שאנו נמצאים בתוך המחלקה, אין מניעה לגשת‬ ‫למשתנים באופן ישיר ולשנותם.‬
  • 3. ‫כמו כן, נזכור שככל שנוגע לגישה לאובייקט שנוצר, אנו יכולים להתייחס אליו כשם שנתייחס למבנה רגיל: כאשר אנו‬ ‫יוצרים את האובייקט במחסנית, הגישה אליו תהיה באמצעות "." וכאשר אנו יוצרים אותו בערימה הגישה אליו תהיה‬ ‫באמצעות ">-". על הגדרת אובייקטים במחסנית ובערימה – מיד.‬ ‫יצירה של אובייקטים מטיפוס המחלקה שהגדרנו תתבצע באופן זהה ליצירת אובייקטים מטיפוסים השמורים כגון‬ ‫‪ ... int, double‬כך שאם בדוגמא שלנו יצרנו מחלקה שנקראת ‪ ,Robot‬אז יצירת רובוט בשם 2‪ r2d‬במחסנית תהיה‬ ‫;2‪.Robot r2d‬‬ ‫כעת, נגדיר את שם הרובוט באמצעות פונקצית התיווך ‪r2d2.SetName ("R2D2"); :SetName‬‬ ‫נשים לב שהגישה היא דרך האובייקט עצמו ולא דרך המחלקה (‪ r2d2.Set‬ולא ‪.)Robot.Set‬‬ ‫כדי לקבל את רמת החוכמה של 2‪ , R2D‬אנו ניגש באמצעות פונקצית התיווך כך:‬ ‫;)(‪.r2d2.GetSmartLevel‬‬ ‫כעת, נבנה פונקציה שמציגה לנו את מכלול הנתונים לגבי רובוט מסוים. על מנת לבצע זאת, נבחין בתכונה שציינו קודם‬ ‫לכן: היות והפונקציה נבנית בגבולות המחלקה, אין לנו צורך בפונקציית התיווך, ואנו יכולים לגשת באופן ישיר לכל‬ ‫משתנה פרטי כאילו היה ציבורי וכמובן שזאת מבלי לסתור את האמור עד כה, שהרי כל עוד שאנו בגבולות המחלקה, אין‬ ‫שום מניעה מאיתנו לגשת למשתנים. המניעה באה על מנת לא לאפשר גישה שכזו מבחוץ. ועל כן, פונקציה שכזו תיראה‬ ‫כך: } ;‪GetToKnowRobot() { cout << Name << " " << SmartLevel << " " << IsHappy‬‬ ‫ואז: ;)(‪r2d2.getToKnowRobot‬‬ ‫היות ואובייקטים ממחלקות מסוימות יכולים להיות "כבדים" והזזתם ממקום למקום דרך המחסנית עלולה לעלות מחיר‬ ‫כבד של פעולות מעבד וזיכרון, אנו נעדיף לבצע את העבודה דרך הערימה.‬ ‫נשים לב שמדובר בעבודה עם מצביעים ולכן אנו נצטרך להיזהר ממצבים בהם האובייקט יהיה בזיכרון ויצרוך משאבים, אך‬ ‫אנו נאבד גישה אליו.‬ ‫ביצירת אובייקט בערימה, אנו נרגיש בשני שינויים עיקריים בהתנהלות שלנו: היצירה תתבצע באופן הבא:‬ ‫;)( ‪Robot * OptimusPrime = new Robot‬‬ ‫;)"‪OptimusPrime -> SetName("Optimus Prime‬‬ ‫והגישה אליו תתבצע באופן הבא:‬