עוצמת ההורשה מה הופך את ההורשה לכלי כל כך עוצמתי? מעבר לכך שהוא מקל בהגדרת מחלקות חדשות על סמך מחלקות קיימות, יש לנו אפשרות להתייחס לאובייקט מסויים בכמה אופנים. בואו ניקח מחלקת צעצוע. אנחנו מעונינים להגדיר מספר סוגי צעצועים שמוצעים למכירה: נגדיר מחלקת על צעצוע Toy public class Toy private string toyname; private double price; public Toy (string toyname, double price) this.toyname = toyname; this.price = price; public string GetToyName()return this.toyname; public double GetPrice()return this.price; public override string ToString () return string.format ("0 costs 1 NIS", GetToyName(), GetPrice()); כעת נגדיר מחלקת דובים Bears( )Teddy שניתן לרכוש אותם בשלושה גדלים. עבור הדוב הגדול נוסיף למחיר הבסיס 15%, עבור הדוב הבינוני נוסיף 7% ועבור הדוב הקטן נשלם את המחיר הבסיסי. enum Size LARGE,MEDIUM,SMALL;
public TeddyBear : Toy private Size bearsize; שיטה בונה // public TeddyBear (string toyname, double price, Size bearsize) : base (toyname,price) מוסיפים רק את החלק הנוסף // bearsize; this.bearsize = public???? double GetPrice() חישוב המחיר אינו החישוב הרגיל אלא צריך לקחת בחשבון גודל הדובי // if (bearsize == Size.LARGE) return base.getprice() * 1.15; if (bearsize == Size.MEDIUM) return base.getprice() * 1.07; return base.getprice(); public Size GetSize()return this.bearsize; public override string ToString() return string.format ("0 Teddy bear called 1", size, base.tostring()); כמו כן נגדיר בובה. לבובות יש גם תוספות ולכן העלות תהיה מחיר הבסיס ועוד עלות התוספות. public Doll : Toy private double priceofaccessories;
public Doll (string dollname, double price, double poa) : base (dollname, price) this.priceofaccessories = poa; גם כאן אני אצטרך לשנות את תחשיב עלות הצעצוע // public????????? double GetPrice() return base.getprice() + this.priceofaccessories; public double GetAccessoriePrice()return priceofaccessories; public override string ToString () return string.format ("Doll named 0 and has 1 NIS worth of Accessories", base.tostring( ), priceofaccessories); יש לי אפשרות להגדיר 3 סוגי צעצועים. אחד כללי שיש לו רק שם ומחיר ושניים אחרים שיש בנוסף למאפיינים האלו עוד מאפיינים ייחודיים להם. עד כאן כמו שהדגמנו: Toy t = new Toy ("Bicycle", 800); TeddyBear bear = new TeddyBear ("Winnie", 120.00, Size.Large); Doll doll = new Doll ("Barbie", 85.00, 32.00); אין כאן שום חידוש אבל... מה קורה אם אני יכולה לבחור או זה, או זה או זה ולשמור אותו במשתנה אחיד??? איזה משתנה תתאים לכל סוגי האובייקטים.
לפי היארכיית ההורשה כולם מוגדרים כסוג של צעצוע דהיינו שהמכנה המשותף לכולם הוא שכולם צעצועים. השינוי כאן הוא שלמרות בובה או דובי אינו רק צעצוע, אפשר לשמור את האובייקט שלנו במשתנה של צעצוע Toy t = new TeddyBear ("Winnie", 120.00, Size.Large); או לחילופין Toy t = new Doll ("Barbie", 85.00, 32.00); כאן יש משהו חדש שלא נתקלנו בו קודם. אפשר להגדיר משתנה כלשהו אבל לשמור בו אובייקט מסוג שאינו בדיוק מהסוג של המשתנה. זה לא פרוץ לחלוטין אבל צריך לשים לזה לב. מותר לשים אובייקט במשתנה שהוא מהסוג שלו או אחד מהמחלקות שממנו הוא יורש. כאן מתעוררת בעיה קטנה: t.getprice(); ראינו שלכל מחלקה יש מימוש שונה לחישוב מחיר. עבור צעצוע רגיל, אין שום חישוב אבל לדובי ולבובה יש נוסחא שלו. האם עבור Winnie אני אקבל 120.00 או אקבל 138.00 האם יבצע את הפעולה של Toy כי למעשה אני מוגדר רק כ- Toy או שמא ישתמש בפעולה של TeddyBear כי בפועל האובייקט הוא מסוג.TeddyBear האם אנחנו יכולים להחליט מה אנחנו רוצים. לאלו שמתכנתים ב- #C, יש לנו שליטה ואנחנו יכולים להחליט האם אנחנו רוצים"לדרוס" את הפעולה של Toy ולהפעיל את הפעולה של.TeddyBear ב- Java, אין שום בחירה ותמיד קורה דריסה. דריסה : המערכת מבצעת פעולה לא של המחלקה המוצהרת )Toy( אלא של המחלקה האמיתית.)TeddyBear( אנחנו בעצם איננו יכולים לדעת באמת מה מבצע התוכנית. ב- #C כדי לאפשר דריסה, אנחנו חייבים להצהיר שהפעולה היא "ברת דריסה" כלומר ניתן לדרוס אותם. המילה השמורה שמצהירה שניתן לדרוס היא virtual לדוגמא שלנו במחלקת Toy נוסיף את המילה :virtual public virtual double GetPrice() return this.price; ובמחלקת TeddyBear נוסיף מילה שמורה override שמאפשרת לו לדרוס את הפעולה המוגדרת כ- virtual )נחליף את סימני השאלה שהגדרתי קודם( public override double GetPrice().
איפה זה שימושי: אני רוצה להגדיר חנות צעצועים ואני בונה מערך של צעצועים שיוכל להכיל את כל סוגי הצעצעים Toy [] toys = new Toy [3]; toys[0] = new Toy ("Bicycle", 800); toys[1] = new TeddyBear ("Winnie", 120.00, Size.Large); toys [2] = new Doll ("Barbie", 85.00, 32.00); for (int i=0; i < toys.length; i++) Console.WriteLine (toys[i].getprice()); מה שאני אקבל זה שורה ראשונה:, 800.00 שורה שניה 138.00 ושורה שלישית 117.00 כלומר כל אחד מהאובייקטים מפעיל את ה- GetPrice() של האובייקט האמיתי שלו. שאלה למחשבה: מה יודפס ב-() ToString האם יודפס המחיר של Toy או המחיר לפי סוג האובייקט. חשוב על זה תרגילים: הגדר מחלקת ספר. המחלקה מכילה שם ספר, שם מחבר, מחיר. יש להגדיר ToString() לכל מאפיין כמו כן יש להגדיר Setter/Getter הגדר מחלקת ספר במבצע המכילה שם ספר, שם מחבר, מחיר והנחה. יש להגדיר פעולה Setter/Getter ו- ToString() כולל GetPrice המחזיר את המחיר הסופי של הספר. כתוב תוכנית ראשית ששואלת האם אתה מעוניין לקלוט ספר או ספר ולהדפיס את שם הספר לפניך קטע קוד. עקוב על המחלקות והצג מה יודפס.1.2 class A private int a; public A (int a)this.a = a; public int GetA()return this.a; public void SetA(int a)this.a = a; public virtual int Add() return this.a; public override string ToString() return "Inside A" + Add().ToString();
class B:A private int b; public B (int a, int b):base (a)this.b = b; public int GetB()return this.b; public void SetB(int b)this.b = b; public override int Add () return base.add() + b; public override string ToString() return "Inside B Too \n" + base.tostring(); class Main public static void Main (string[] args) A[] a = new A[2]; a [0] = new A (5); B b = new B(3,6); a[1] = b; for (int i=0; i < 2; i++) Console.WriteLine(a[i]); b.setb (1); b.seta(12); a[0].seta (2); for (int i=0; i < 2; i++) Console.WriteLine(a[i]);