הורשה - שיעור פתיחה


היכרות ראשונית עם הורשה ומבני מחלקות

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

מטרות הלמידה

מטרות הלמידה

בסיום פרק זה תוכלו:

  • להבין את המושג “הורשה” בתכנות מונחה עצמים
  • לסרטט היררכיות של הורשה והכלה בין מחלקות
  • להבין ולממש את עקרון “הוא סוג של” (IS-A)
  • לקרוא, לממש, ולצייר דיאגרמות UML

כתיבה של הורשה ב-C#

public class Animal { }
public class Dog : Animal   // Dog inherits Animal
{

}

תרשים UML של שרשרת הורשה

לעיתים נציג מחלקות בתרשים UML. החץ כלפי מעלה - מהיורשת אל מחלקת הבסיס. על צורת הכתיבה של UML יוסבר בהמשך

classDiagram direction TB class Organism { -string name -int age +ToString() string } class Mammal { -bool hasFur +GetHasFur() bool +SetHasFur(bool) } class Dog { -string breed +GetBreed() string +SetBreed(string) } Organism <|-- Mammal : חץ מנגזרת לבסיס Mammal <|-- Dog : ראש חץ חלול לציון הורשה

מימוש בקוד

למימוש פשוט
public class Organism
{
    private string name;
    private int age;

    public Organism(string name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public override string ToString() => $"{name}, age {age}";
}

public class Mammal : Organism
{
    private bool hasFur;

    public Mammal(string name, int age, bool hasFur) : base(name, age)
    {
        this.hasFur = hasFur;
    }

    public bool GetHasFur() => hasFur; 
    public void SetHasFur(bool hasFur) => this.hasFur = hasFur; 
}

public class Dog : Mammal
{
    private string breed;

    public Dog(string name, int age, string breed)
        : base(name, age, true)
    {
        this.breed = breed;
    }

    public string GetBreed() => breed; 
    public void SetBreed(string breed) => this.breed = breed; 
}

סדר פעולות ביצירת עצם ממחלקה יורשת:

  • אם לא מצוין (...)base בבנאי של מחלקה יורשת, ייקרא אוטומטית בנאי ברירת מחדל של מחלקת הבסיס (אם קיים).
  • סדר היצירה של אובייקט יורש הוא: קודם בנאי הבסיס, אחריו בנאי המחלקה הנגזרת.

שימוש: הדגמה עם מערך עצמים

Dog[] kennel = new Dog[]
{
    new Dog("Rex", 5, "Labrador"),
    new Dog("Luna", 2, "Husky"),
    new Dog("Milo", 3, "Beagle")
};

for (int i = 0; i < kennel.Length; i++)
{
    Console.WriteLine(
        $"{i}: {kennel[i]}, breed {kennel[i].GetBreed()}");
}

למימוש מעט יותר משוכלל
classDiagram direction TB class Organism { -static int counter -readonly int id -string name -int age +GetId() int +ToString() string } class Mammal { -bool hasFur +GetHasFur() bool +SetHasFur(bool) +ToString() string } class Dog { -string breed +GetBreed() string +SetBreed(string) +ToString() string } Organism <|-- Mammal Mammal <|-- Dog

בגרסה זו השינויים הבאים:

  1. שימוש במשתנה סטטי ליצירת מונה של מופעים והקצאת id לכל עצם
  2. למחלקות השונות הוגדר ()override string ToString שמחזיר יצוג של העצם
  3. בכל ToString נוספה קריאה לאותה הפעולה במחלקת הבסיס. כך שכל מחלקה מטפלת ומוסיפה רק את המידע שלה
public class Organism
{
    private static int counter = 0;   // counts instances
    private readonly int id;          // assigned unique id
    private string name;
    private int age;

    public Organism(string name, int age)
    {
        this.id = counter++;
        this.name = name;
        this.age = age;
    }

    public string GetName() { return name; }
    public void SetName(string name) { this.name = name; }
    public int GetAge() { return age; }
    public void SetAge(int age) { this.age = age; }
    public int GetId() => id;
    public override string ToString() => $"{id}: {name}, age {age}";
}

public class Mammal : Organism
{
    private bool hasFur;

    public Mammal(string name, int age, bool hasFur) : base(name, age)
    {
        this.hasFur = hasFur;
    }

    public bool GetHasFur() => hasFur;
    public void SetHasFur(bool hasFur) => this.hasFur = hasFur;
}

public class Dog : Mammal
{
    private string breed;

    public Dog(string name, int age, string breed)
        : base(name, age, true)
    {
        this.breed = breed;
    }

    public string GetBreed() => breed;
    public void SetBreed(string value) => breed = value;
    public override string ToString() =>
        base.ToString() + $", breed {breed}";
}

// Example usage
class Program
{
    static void Main()
    {
        Dog[] kennel = new Dog[]
        {
            new Dog("Rex", 5, "Labrador"),
            new Dog("Luna", 2, "Husky"),
            new Dog("Milo", 3, "Beagle")
        };

        foreach (var dog in kennel)
            Console.WriteLine(dog);

    }
}

פלט

0: Rex, age 5, breed Labrador
1: Luna, age 2, breed Husky
2: Milo, age 3, breed Beagle

רמות גישה (Access Modifiers)

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

טבלה מסכמת:

נגישות access modifier
נגיש מכל מקום בפרויקט. public
נגיש רק מתוך המחלקה עצמה. private
נגיש מתוך המחלקה עצמה ומתוך מחלקות שיורשות ממנה. protected
נגיש לכל הקבצים באותו Assembly (בבחינת בגרות נרשום public). internal

“הוא סוג של” – עקרון ה־IS A

ב-OOP אנו משתמשים בהורשה ליצירת יחס של “הוא סוג של” (IS A).
מחלקת בן יורשת ממחלקת אב ולכן היא סוג של המחלקה שמעליה.
ניתן לבדוק זאת בזמן ריצה בעזרת המילה השמורה is.


דוגמת קוד
public class Animal { }
public class Dog : Animal 
{
    public void Bark() => Console.WriteLine("Woof!");
}

class Program
{
    static void Main()
    {
        Animal a1 = new Dog();
        Animal a2 = new Animal();

        if (a1 is Dog d)  // pattern matching
            d.Bark();   // a1 הוא סוג של Dog → Woof!
        if (a2 is Dog) 
            Console.WriteLine("a2 הוא כלב"); 
        else 
            Console.WriteLine("a2 אינו כלב");
    }
}

סיכום is:

  • IS A מייצג הורשה – כלב הוא סוג של בעל־חיים.
  • is בודק אם אובייקט שייך לטיפוס מסוים.
  • עם pattern matching (obj is Dog d) אפשר גם לבצע המרה בטוחה לאותו טיפוס.

סיכום

  • הורשה יוצרת יחס “הוא סוג של”.
  • סדר בנאים: מהבסיס אל הנגזר.
  • שימוש ב-private, protected, public, internal חשוב כדי לשלוט בגישה.
  • בבגרות נרשום public ולא internal.

תרגיל: הוסיפו מחלקה נוספת WorkingDog עם שדה Task ובנאי מתאים, והדגימו קריאות ל-Getters/Setters.


Campus playlist - הורשה בלבד

המשך - הרחבת נושא הורשה

המשך - הרחבה בנושא בנאים

קמפוס - מצגת הורשה

קמפוס - מצגת מחלקות אבסטרקטיות