# ירושה — virtual ו-override📖 שיעור

## מה זה?

תארו לעצמכם מערכת עם `Employee` ו-`Manager` — למנהל יש את כל מה שיש לעובד רגיל (שם, משכורת) ועוד קצת (צוות שהוא מנהל). בלי ירושה, `Manager` היה מעתיק-מדביק את כל השדות והמתודות של `Employee` מחדש — כפילות שמסתכנת בחוסר-סנכרון אם `Employee` משתנה. ירושה (`: BaseClass`) פותרת את זה: `Manager` "יורש" אוטומטית את כל מה שיש ל-`Employee`, ומוסיף רק את מה שייחודי לו.

## מילות מפתח שחשוב לזכור

• Base Class (מחלקת בסיס) — המחלקה שממנה יורשים; מגדירה את ההתנהגות המשותפת

• Derived Class (מחלקה נגזרת) — המחלקה שיורשת; מקבלת אוטומטית את כל מה שב-Base Class

• `virtual` — מסמן מתודה ב-Base Class כ"ניתנת לשכתוב" על ידי מחלקות יורשות

• `override` — מחלקה יורשת מגדירה מחדש מתודה `virtual`, עם התנהגות ייחודית לה

• `base` — מתייחס למימוש של המחלקה שממנה יורשים; שימושי לקרוא למימוש המקורי מתוך override

```csharp
class Employee
{
    public string Name;
    public double Salary;

    public Employee(string name, double salary)
    {
        Name = name;
        Salary = salary;
    }

    public virtual string Describe()
    {
        return $"{Name}, employee, salary {Salary}";
    }
}

class Manager : Employee   // Manager inherits from Employee
{
    public List<string> TeamMembers = new List<string>();

    public Manager(string name, double salary) : base(name, salary) { }

    public override string Describe()
    {
        return $"{base.Describe()}, manages a team of {TeamMembers.Count} people";
    }
}
```

```csharp
Employee employee = new Employee("Dana", 15000);
Manager manager = new Manager("Avi", 22000);
manager.TeamMembers.Add("Rotem");

Console.WriteLine(employee.Describe());   // Dana, employee, salary 15000
Console.WriteLine(manager.Describe());    // Avi, employee, salary 22000, manages a team of 1 people
```

```mermaid
classDiagram
    class Employee {
      +string Name
      +double Salary
      +Describe() virtual
    }
    class Manager {
      +List~string~ TeamMembers
      +Describe() override
    }
    Employee <|-- Manager
```

## הסבר עיקרי

`: base(name, salary)` — קונסטרוקטור של מחלקה יורשת חייב לוודא שהקונסטרוקטור של ה-Base Class רץ קודם, כדי ש-`Name`/`Salary` יאותחלו כראוי. התחביר `: base(...)` מעביר את הפרמטרים לקונסטרוקטור של `Employee` באופן מפורש.

למה `virtual` ו-`override` הכרחיים ביחד — בלי `virtual` על `Describe` ב-`Employee`, C# לא הייתה מרשה ל-`Manager` "לשכתב" את ההתנהגות — כל קריאה הייתה מריצה תמיד את הגרסה המקורית. `virtual` הוא "רישיון לשכתוב"; `override` הוא המימוש המחודש בפועל במחלקה היורשת.

`base.Describe()` — בתוך ה-`override`, אפשר לקרוא למימוש **המקורי** של ה-Base Class עם `base.Describe()`, ולהוסיף עליו — במקום לשכתב הכל מאפס. בדוגמה, `Manager.Describe` משתמש בתיאור הבסיסי של `Employee` ומוסיף עליו את פרטי הצוות — לא כותב את שם המשכורת מחדש.

## יתרונות

ירושה מונעת שכפול קוד בין מחלקות קשורות; `virtual`/`override` מאפשרים לכל מחלקה יורשת להתאים התנהגות ספציפית לה, תוך שמירה על ממשק אחיד; `base` מאפשר להרחיב התנהגות קיימת בלי לשכתב אותה מאפס.

## חסרונות

ירושה עמוקה מדי (מחלקה יורשת ממחלקה שיורשת ממחלקה...) הופכת קוד לקשה למעקב; שינוי במחלקת בסיס עלול להשפיע (לפעמים בהפתעה) על כל היורשות ממנה — "שביר" יותר מהרכבה (Composition), נושא שיוזכר בהמשך הקורס.

## נקודות חשובות

• Derived Class מקבל אוטומטית את כל השדות/המתודות `public`/`protected` של ה-Base Class

• `virtual` ב-Base Class מאפשר `override` במחלקה יורשת; בלי `virtual` אי אפשר לשכתב

• `base(...)` בקונסטרוקטור מעביר פרמטרים לקונסטרוקטור של מחלקת הבסיס

• `base.Method()` בתוך override קורא למימוש המקורי, לא רק "מדלג" עליו

## טעויות נפוצות

• לשכוח `virtual` על מתודה ב-Base Class ואז לתהות למה `override` לא מתקמפל

• לא לקרוא לקונסטרוקטור הבסיס (`: base(...)`) ולהשאיר שדות יורשים לא מאותחלים

• להשתמש בירושה כשבפועל אין קשר "הוא-סוג-של" אמיתי בין המחלקות (למשל `Car : Engine` — רכב הוא לא סוג של מנוע, הוא **מכיל** מנוע)

## סיכום

ירושה (`class Manager : Employee`) מאפשרת למחלקה נגזרת לקבל אוטומטית שדות והתנהגות ממחלקת בסיס, ולהוסיף או לשנות רק את מה שייחודי לה. `virtual` על ה-Base Class מאפשר `override` במחלקה היורשת, ו-`base` מאפשר גישה למימוש המקורי — גם לקונסטרוקטור וגם למתודות — כדי להרחיב ולא לשכפל.

## דוקומנטציה רשמית

[Microsoft Learn — Inheritance](https://learn.microsoft.com/dotnet/csharp/fundamentals/object-oriented/inheritance)

---

## תרגילים

### תרגיל 1 — ירושה בסיסית

**המשימה:** הגדירו `class Animal` עם `Name` ומתודת `virtual` בשם `MakeSound()` שמדפיסה "השמעת קול כללית". הגדירו `class Dog : Animal` עם `override` ל-`MakeSound()` שמדפיסה "הב הב!".

**בדיקה:** קריאה ל-`MakeSound()` על מופע `Animal` מדפיסה את הקול הכללי; על מופע `Dog` מדפיסה "הב הב!".

### תרגיל 2 — base בקונסטרוקטור ובמתודה

**המשימה:** בדוגמת `Employee`/`Manager` מהשיעור, הוסיפו למחלקת `Manager` שדה `Department`, קונסטרוקטור שמעביר אותו דרך `: base(...)`, ומתודת `Describe` שמשתמשת ב-`base.Describe()` ומוסיפה את המחלקה.

**בדיקה:** הדפסת `manager.Describe()` כוללת גם את פרטי `Employee` המקוריים וגם את המחלקה, בלי כפילות קוד.

---

## פרויקט מסכם

**המשימה:** בנו היררכיית `Shape` פשוטה: `class Shape` עם `virtual double Area()` שמחזירה `0`, ושתי מחלקות יורשות: `Circle` (עם `Radius`) ו-`Rectangle` (עם `Width`/`Height`), כל אחת עם `override` נכון לחישוב השטח שלה.

**דרישות:**
1. `Shape` עם קונסטרוקטור בסיסי ומתודת `virtual Area()`
2. `Circle : Shape` ו-`Rectangle : Shape`, כל אחת עם `override Area()` נכון (`π * r²` ו-`width * height`)
3. `List<Shape>` שמכילה כמה עיגולים ומלבנים, ולולאה שמדפיסה את השטח של כל אחד עם `foreach`

**בדיקה:** הלולאה מדפיסה שטח נכון לכל צורה, למרות שכולן מטופלות דרך אותו טיפוס `Shape` ברשימה — זו בדיוק ההוכחה שכל מופע "יודע" להריץ את ה-`override` הנכון שלו.

## מה בפרק הבא

בפרק הבא — **Abstract Classes, sealed ופולימורפיזם**: מה קורה כשמחלקת בסיס לא אמורה בכלל להיות ניתנת ליצירה ישירה, ואיך C# אוכפת את זה.
