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

קוד OOP ואלמנטים של אבטחת סייבר משתלבים על מסך דיגיטלי.

המאמר עובר על המושגים החשובים עם דוגמאות בסגנון של C# וג׳אווה, שהן השפות שנלמדות בדרך כלל בהכנה, ומסביר איפה נופלים בשאלות. אין רשימה רשמית של שאלות, והתוכן מבוסס על הנושאים הנפוצים בהכנה לשאלון.

מחלקה, אובייקט ובנאי

מחלקה (Class) היא תבנית שמתארת תכונות והתנהגות, ואובייקט (Object) הוא מופע שנוצר ממנה. אם Car היא מחלקה עם צבע ומהירות, אז המכונית הכחולה שלכם היא אובייקט אחד ומכונית אדומה אחרת היא אובייקט אחר, שלכל אחד מהם ערכים משלו.

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

כימוס: מי רואה מה

כימוס (Encapsulation) אומר שהמידע הפנימי של האובייקט מוסתר, והגישה אליו נעשית דרך שיטות מוגדרות. באמצעות משתנים פרטיים (private) ושיטות ציבוריות (public) אפשר לשלוט בערכים שנכנסים, למשל למנוע גיל שלילי.

בשאלות מופיעות לעיתים ההרשאות השונות: public נגיש לכולם, private רק בתוך המחלקה, ו-protected בתוך המחלקה וביורשים שלה. שאלה טיפוסית תציג ניסיון גישה למשתנה פרטי מבחוץ ותשאל האם הקוד יתקמפל.

ירושה והרשאות של מחלקת האב

ירושה (Inheritance) מאפשרת למחלקה חדשה להשתמש בתכונות ובשיטות של מחלקה קיימת ולהרחיב אותן. מחלקת Dog שיורשת מ-Animal מקבלת את כל מה שיש ב-Animal ומוסיפה התנהגות משלה.

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

פולימורפיזם: אותה קריאה, התנהגות שונה

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

כדי שזה יעבוד, השיטה צריכה להיות וירטואלית. ב-C# מסמנים אותה virtual במחלקת האב ו-override במחלקה היורשת, ובג׳אווה שיטות רגילות הן וירטואליות כברירת מחדל. שאלות רבות בונות מלכודת סביב ההבדל בין טיפוס המשתנה לבין הטיפוס האמיתי של האובייקט.

Override מול Overload

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

דוגמה לשאלה: מה יודפס

נניח שיש מחלקה Animal עם שיטה Speak שמדפיסה Animal, ומחלקה Dog שיורשת ממנה ודורסת את Speak כך שתדפיס Woof. הקוד יוצר משתנה מסוג Animal שמצביע על אובייקט חדש מסוג Dog וקורא לשיטה.

אם Speak מוגדרת כוירטואלית והיא נדרסת עם override, יודפס Woof, כי נבחר המימוש של הסוג האמיתי. אם היא לא וירטואלית והמחלקה היורשת רק מסתירה אותה, יודפס Animal, כי הבחירה נעשית לפי טיפוס המשתנה. שינוי קטן בהגדרה הופך את התשובה, וזה בדיוק מה ששאלות אוהבות לבדוק.

המילים this, base ו-super

this מתייחס לאובייקט הנוכחי, ומשמש בין היתר להבחין בין תכונה של האובייקט לבין פרמטר עם אותו שם. base ב-C# ו-super בג׳אווה מתייחסים למחלקת האב, ומאפשרים לקרוא לבנאי שלה או לשיטה שנדרסה.

שאלות בנושא יבדקו לעיתים אם הקריאה לבנאי של מחלקת האב מופיעה בתחילת הבנאי, או מה יקרה כשלמחלקת האב אין בנאי ברירת מחדל והיורשת לא קוראת לבנאי אחר במפורש.

מחלקה אבסטרקטית וממשק

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

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

static ומשתני מחלקה

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

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

שוויון והשוואה: == מול Equals

בשפות רבות האופרטור == משווה בין הפניות, כלומר האם שני משתנים מצביעים על אותו אובייקט. השיטה Equals נועדה להשוות תוכן, והיא דורסת ברירת מחדל בחלק מהמחלקות, למשל String.

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

OOP בפייתון: הבדלים שכדאי להכיר

גם בפייתון יש מחלקות, ירושה ופולימורפיזם, אבל הגישה גמישה יותר. אין מילות מפתח private ו-public מחייבות, ובמקומן יש מוסכמה של קו תחתון שמסמן שתכונה אינה מיועדת לשימוש חיצוני. הבנאי נקרא init, והפרמטר הראשון של כל שיטה הוא self.

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

טעויות נפוצות בשאלות OOP

הטעות השכיחה ביותר היא להתבלבל בין טיפוס המשתנה לטיפוס האובייקט. טעות נוספת היא לשכוח את סדר הבנאים בירושה, או להניח ששיטה נדרסת בלי לבדוק שהיא אכן מסומנת כוירטואלית.

יש גם מי שמפספסים גישה לחברים פרטיים או שימוש בשיטה סטטית על אובייקט. כדי להימנע מכך, כדאי לעבור על כל שורה בקוד ולשאול מה ההרשאה, מה הטיפוס ומה השיטה שנבחרת, לפני שמכריעים על התשובה.

איפה OOP פוגש את הסייבר

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

גם חולשות נפוצות קשורות לנושא: נעילה לא נכונה של גישה לאובייקט משותף, חשיפה של תכונות שהיו צריכות להיות פרטיות, או אמון בקלט שמגיע ממחלקה חיצונית. לכן כדאי לראות ב-OOP חלק מהחשיבה האבטחתית, ולא רק נושא שנדרש לשאלון.

איך פותרים שאלת OOP בשאלון

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

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

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

איך אקדמיית המתכנתים מלמדת OOP

בקורס ההכנה לגאמא סייבר של אקדמיית המתכנתים יש פרקים ייעודיים לשפות #C וג׳אווה ולתכנות מונחה עצמים, בתוך 10 פרקי הליבה. הלימוד מתקיים ב-30 מפגשי לייב עם מרצה בוגר יחידה ומתרגל אישי צמוד עד סוף י״ב.

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

שאלות נפוצות בנושא OOP בשאלון גאמא סייבר

האם צריך לדעת גם ג׳אווה וגם C#?

לא בהכרח. העקרונות זהים ברובם, ומי שמבין OOP באחת מהשפות יכול לקרוא קוד בשנייה. כדאי להכיר את ההבדלים התחביריים העיקריים, כמו virtual ו-override ב-C#.

מה חשוב יותר להבין: ירושה או פולימורפיזם?

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

איך מתרגלים OOP בלי לשנן?

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

האם OOP מופיע גם בשלבים אחרים של המיון?

הוא נבדק בעיקר בשאלון הידע, אבל ההבנה שלו עוזרת גם בסדנה, כשכותבים או קוראים קוד מורכב יותר. לכן הידע הזה משתלם לאורך כל התהליך.

רוצים לתרגל OOP עם מרצה בוגר יחידה ועם סימולציות אמיתיות? אפשר לקרוא על התוכנית המלאה בעמוד קורס ההכנה לגאמא סייבר.