שאלות כלליות מדעי המחשב בגרות בנושא תכנות מונחה עצ...
שאלות כלליות מדעי המחשב בגרות בנושא תכנות מונחה עצמים, תמ"ע
שאלה ראשונה:
נניח וכל אחת מהמחלקות הבאות מקיימות את הירושה הבאה:
A extends Object
B extends A
C extends B
D extends C
בנוסף ידוע כי לכל מחלקה יש פעולה ייחודית:
A- print()
B-max()
C-min()
D-next()
כשמשנים נקות מבט למחלקה מסוימת, ואני רוצה להפעיל פעולה שיש רק למחלקה אחת, אז המחלקה תהיה חייבת להיות המחלקה שיש לה את הפעולה או שזו יכולה להיות מחלקה שיורשת ממנה, ולכן גם לה יש את הפעולה
לדוגמה:
A ac=new C()
ואני רוצה להפעיל על ac את הפעולה max של B אז איך אני עושה את זה באופן חוקי?
תשובה ראשונה:
באופן עקרוני כן, אם את יוצרת משתנה מטיפוס C אזי אז יוצרת משתנה מטיפוס Object,A,B,C ולכן באופן פוטנציאלי את יכולה להשתמש בכל אחת ואחת מהפונקציות שיש בכל אחד מהמחלקות הללו.
יש להתחשב בעקרונות ההורשה והפולימורפיזם:
העמסה / דריסה.. כך שאם במקרה למחלקה C יש גם פונקציית max עם החתימה הזהה בידיוק לזו שיש במחלקה C, אזי היא תדרוס אותה בזמן ריצה.
דבר נוסף חשוב גם להתחשב בעקרונות הכימוס:
כל פונקציה תכונה אשר מוגדרת כ-private לשימוש אך ורק במחלקה בה היא נכתבה.
כך פונקציה או תכונה אשר מוגדרת כ-protected ניתנת לשימוש אך ורק במחלקה בה היא נכתבה או במחלקות היורשות.
כל פונקציה או תכונה אשר מוגדרת כ public ניתנת לשימוש מכל מקום.
שאלה שנייה:
נובע מהשאלה הקודמת, אם אני רוצה לעשות המרה אז הטיפוס תמיד צריך להיות הטיפוס שאני ממירה אליו או שאפשר להשתמש בטיפוס אחר שיורש ממנו?
תשובה שנייה:
כעיקרון אם מדובר במשתנה מטיפוס C, אזי ניתן להמיר אותו ל-Object,A,B,C במידת הצורך.
בכל מקרה נהוג להשתמש במילה השמורה instanceof על מנת לוודא באמת האם אותו משתנה שייך למחלקה מסוימת (על מנת למנוע שגיאת זמן ריצה).
שאלה שלישית:
כשאני מנסה להמיר, הטיפוס שאני ממירה אליו חייב להיות תואם את הזמן קומפילציה?
תשובה שלישית:
זה לא חייב להיות תואם את זמן הקומפילציה. כמו בדוגמה הקודמת:
A ac = new C();
ניתן לבצע המרה:
((B) ac)
שאלה רביעי:
מה הכוונה כשמשווים שמות של עצמים? לדוגמה:
A a1=new A();
A ab =new B();
a1=ab;
אז עכשיו a1 הוא בעצם שווה לזמן קומפילציה של ab? לא הצלחתי להבין פשוט מה זה אומר כשמשווים בין עצמים, ואיזה עצם זה משנה.
תשובה רביעית:
בעצם רק שמשתמשים במילה new (קוראת לבנאי של המחלקה), אנחנו יוצרים עצם חדש, ומקבלים כתובת (רפרנס) עבורו.
עצם ההשוואה a1=ab, לא יוצרת שום דבר חדש, וגורמת לכך ש-a1 יחזיק ברפרנס של המשתנה ab.
צריך לזכור ש reference של הבן לא יכול להצביע על reference של אביו/סביו..
כלומר מצב תקין הוא:
father = father
father = son
ומצב לא תקין
שאלה חמישית:
בנוגע לדריסת פעולות, מיד הולכים לפונקציה שהכי נמוכה ?
תשובה חמישית:
על מנת שזמן הקומפילציה יעבור הקומפיילר (המהדר) חייב למצוא פונקציה מתאימה.
רק בזמן ריצה, כאשר רק שם אנחנו מגלים, שהעצם בזמן הקומפילציה הוא בכלל מחלקה שיורשת (בן, נכד, נין) מתחילים לחפש את הפונקציה הכי נמוכה שזהה בחתימה שלה לפונקציה שהקומפיילר זיהה.
במידה ומצאנו, הפונקציה של הבן, נכד, נין מבצעת דריסה לפעולה שהקומפיילר סימן.
שאלה שישית:
אם יש לי במחלקה שמורישה למחלקה אחרת ובאותה מחלקה שיורשת (נגיד a ו-b ) ולשתי המחלקות יש את אותה תכונה int x לדוגמה אז כשיש לי משהו כמו- A ab=new B (1,2); ואני רוצה להשתמש בפעולה שיש ב A והיא מקבלת את x ולשתי התכונות קוראים x בשתי המחלקות אז היא תפעל על ה-x של a או של b?
תשובה שישית:
נניח וקיימת המחלקות הבאות:
public class A{
protected int x;
public A(int x)
{
this.x=x;
}
}
public class B extends A{
protected int x;
public B(int x1,int x2)
{
super(x1);
this.x2=x2;
}
}
מבחינת בנאים.. הבעיה נפתרה (ראי כיצד בנינו את הבנאים ושלחנו את ה-x המתאים מבחינתנו לאבא.
מכיוון שבמקרה זה התכונה מוגדרת כ protected ניתן לגשת ישירות לתכונה x של A מתוך B וזאת על ידי שימוש במילה super.
בתוך B: אם נשתמש ב super,x נתכוון ל-x של האבא, ואם נשתמש ב x או this.x נתכוון ל-x של B.
במידה והתכונה x של A הייתה private היינו צריכים להיעזר ב getters או setters של האב (בתקווה שהם protected או public) בשביל לגשת לתכונה x של A מתוך B.