הורשה ופולימורפיזם

0

-פרסומת-

הורשה (תורשה או ירושה- Inheritance) הינה אחד העקרונות הראשיים הבאים לידי ביטוי בתכנות מונחה עצמים (OOP). הורשה מאפשרת לרשת ממחלקה מסויימת את “היכולות” שלה, שהן התכונות והמתודות שלה- איברי המחלקה (Class Members) ע”י מחלקה אחרת שניקראת המחלקה היורשת (Derived-Class/ Sub-Class). המחלקת שממנה ירשו נקראת מחלקת בסיס או מחלקת אב (Base-Class/ SuperClass). בדומה לביולוגיה, ניתן להתייחס למופע מחלקה שהוא אובייקט שלה כאל אובייקט הבן שיש לו את אותן היכולות, הפונקציות והתכונות (attributes) של מחלקת האב (גנים).

-פרסומת-

הורשה, כמו בהכלה (הרכבה- Composition), מאפשרת תיכנות נקי ומהיר יותר הודות לשימוש חוזר בקוד (מיחזור קוד).

ב-JAVA, בניגוד לשפת C++ ניתן לרשת ממחלקה אחת בלבד (כך גם ב-#C), במילים אחרות בשפת ג’אווה לא קיימת הורשה מרובה.

פולימורפיזם (רב צורתיות/ רב- טיפוסיות) היא היכולת של אובייקט שנוצר מטיפוס מסויים להיות בו זמנית אובייקט מטיפוסים אחרים, כך שניתן להריץ עליו מתודות של מחלקות שונות. באמצעות מנגנון הפולימורפיזם ניתן להתייחס למספר אובייקטים בעץ תורשה שהם מסוגים שונים בצורה אחידה דרך מאפיין בסיסי המשותף בינהם. כאשר האובייקטים הם מטיפוסים שונים, ניתן להסתכל על המחלקה המשותפת לכולם (למשל מחלקת Object) ולבנות מערך הפניות לאובייקטים, כאשר ההפניות עצמן מהטיפוס הבסיסי ביותר שמשותף לכולם. ניתן לזמן בכל פעם מתודות השייכות למחלקות שונות באמצעות שימוש בהפניה (רפרנס/ מצביע/ reference) מטיפוסים שונים בעץ התורשה שהיא בחוזקים שונים, כלומר לכל אחת יכולות שונות. למעשה הפניה יכולה להיות חלשה יותר או שווה ביכולותיה לאובייקט המוצבע על ידיה. ככל שיורדים בעץ התורשה, כך המחלקות בעלי יותר יכולות ועל כן הן חזקות יותר. לסיכום, תכונת הפולימורפיזם מאפשרת לבנות מבני נתונים (מערכים, רשימות) המכילים הפניות מטיפוס בסיסי זהה המצביעות לאובייקטים מטיפוסים שונים וברמות שונות על אותו עץ תורשה (היררכיית תורשה) ולהריץ פונקציות מתאימות על כל אובייקט לסוגו על ידי המרת ההפניות למטה (DownCasting).

ב-JAVA, כל אובייקט יורש באופן אוטומטי ממחלקת העל הבסיסית Object ומכאן שכל אובייקט בג’אווה הוא בו זמנית מסוג שני טיפוסים לפחות, מטיפוס האובייקט ומטיפוס Object.

כללים בפולימורפיזם:

-בעבור מתודות הקיימות הן במחלקת הבסיס והן במחלקה היורשת (מתודות דורסות- Overriding Methods), תמיד תרוץ הפונקציה הדורסת הנמוכה ביותר בעץ התורשה (של האובייקט הנגזר- החזק יותר), העדכנית ביותר.

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

-כאשר הפניה חלשה מצביעה על אובייקט חזק יותר, ניתן להריץ דרכה רק פונקציות אשר מופיעות הן במחלקת הבסיס והן במחלקה היורשת או במחלקת הבסיס בלבד! ) כלומר, לא ניתן להריץ פונקציות השייכות לאובייקט החזק ואינן דורסות (שמופיעות רק בו).

כדי להריץ מתודות כאלה יש לבצע המרה למטה (DownCasting) להפניה, להמיר אותה, כך שתיהיה מאותו הטיפוס של האובייקט שבמחלקתו קיימת אותה פונקציה, ובכך להשיב לה כוחות ולהריץ את הפונקציה.

דוגמה בג’אווה:

מוגדרות המחלקות הבאות:

public class  Base{…};

Public class Sub extends Base{….};

מכאן שמחלקת Sub יורשת מ-Base, כלומר Sub היא סוג של Base.

במחלקת Base מוגדרות המתודות:

public Base();

public m1();

public m2(int x, String str);

במחלקת Sub מוגדרות המתודות:

public Sub();

public m1();

public m2(int x);

public m3(String str);

נתבונן בשורות הקוד הבאות:

הצהרות:

Object [] array = new Object[3];

array[0]= new Base();

array[1]= new Sub();

Base base= new Base();

Sub sub = new Sub();

-פרסומת-

Base sub_base = new Sub();

 זימונים:

base.m1();

base.m2(5,”string”);

base.m3(” “);//לא חוקי- שגיאת קומפילציה- לא קיימת פונקציה כזו במחלקה של האובייקט המוצבע

sub.m1();

// הפונקציה m1 תרוץ ממחלקת Sub

sub.m2(1,”string”);

// הפונקציה m2 האומנם לא מוגדרת במחלקה Sub, אך היא כן קיימת בה שכן המחלקה היורשת מכילה את כל הפנקציות של המחלקה הבסיסית (Base).

sub_base.m1();

//תרוץ m1 ממחלקת Sub כי m1 של Base נדרשת על ידיה

sub_base.m2(4,” “);

// המתודה תרוץ ממחלקת הבסיס Base כי היא לא נדרסת במחלקה היורשת.

sub_base.m2(6);

// שגיאת קומפילציה- לא קיימת מתודה בעלת כותרת m2(int) במחלקת Base, היא קיימת ב-Sub היורשת, אך הרפרנס חלש ביחס לאובייקט!

תיקון:

נמיר את ההפניה sub_base להיות מסוג Sub כך שהיא תיהיה חזקה יותר (השבת כוחות- DownCasting):

((Sub)sub_base).m2(6);//תקין!

array[0].m1();//שגוי

array[1].m1();//שגוי

// שני המשפטים הללו יגררו שגיאת קומפילציה משום  שלא קיימת שיטה כזו במחלקת מסוג הרפרפנס Object

תיקון:

if(array[0] instanceof Base){

((Base)array[0]).m1();

((Base)array[1]).m1();

}

במקרה הראשון תרוץ הפונקציה ממחלקת Base, ובמקרה השני ממחלקת Sub (מסוג האובייקט המוצבע).

 

האופרטור instanceof

שם_ממשק/ שם_מחלקה instanceof משתנה (שם_הפניה)

instanceof מחזיר אמת (true) אם ההפניה (בצד שמאל) מצביעה על אובייקט מסוג שם_מחלקה (מצד ימין) או שהאובייקט מממש ממשק מסוג שם_ממשק.

סוג– כלומר קיימת ירושה גם בממשקים וגם בין מחלקות.

-פרסומת-

עשוי לעניין אותך

הגב

לא נפרסם את האימייל שלך.