מה זה?

בשיעורי היסודות ניהלנו תלמיד עם משתנים נפרדים — studentName, studentAge, studentGrade — בלי שום קשר פורמלי ביניהם. אם רוצים 30 תלמידים, צריך 90 משתנים נפרדים (או 3 מערכים מקבילים, שקל לאבד סנכרון ביניהם). מחלקה (class) פותרת את זה: מגדירים “תבנית” אחת שמאגדת יחד את כל השדות שקשורים לישות אחת (תלמיד), ואז יוצרים כמה שרוצים מופעים (objects) של אותה תבנית.

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

• Class — תבנית שמגדירה אילו שדות ומתודות שייכים לישות מסוג מסוים

• Object (Instance) — מופע קונקרטי שנוצר מהתבנית, עם ערכים משלו

• Field — משתנה ששייך למחלקה, מחזיק חלק מהמצב (State) של כל מופע

• Constructor — מתודה מיוחדת שרצה פעם אחת, בזמן יצירת מופע חדש עם new

• this — מתייחס למופע הנוכחי עצמו; מבדיל בין שם הפרמטר לשם השדה כשהם זהים

class Student
{
    // Fields — the state of each instance
    public string Name;
    public int Age;

    // Constructor — runs once, when a new instance is created
    public Student(string name, int age)
    {
        this.Name = name;   // this.Name = the field; name = the parameter
        this.Age = age;
    }
}

Student student1 = new Student("Dana", 20);
Student student2 = new Student("Avi", 22);

Console.WriteLine(student1.Name);   // Dana
Console.WriteLine(student2.Name);   // Avi — a completely separate instance
  flowchart RL
    A["class Student<br/>(template)"] -->|"new Student('Dana', 20)"| B["student1<br/>Name=Dana, Age=20"]
    A -->|"new Student('Avi', 22)"| C["student2<br/>Name=Avi, Age=22"]

הסבר עיקרי

Class מול Object — ה-Class הוא ה"תוכנית" (Blueprint) — הוא לא מחזיק ערכים בעצמו, רק מגדיר אילו שדות יהיו לכל מופע. ה-Object הוא ה"בית שנבנה לפי התוכנית" — כל new Student(...) יוצר מופע עצמאי לגמרי, עם עותק משלו של כל שדה. שינוי ב-student1.Age לא משפיע על student2.Age — הם שני אובייקטים נפרדים לגמרי בזיכרון, בדיוק כמו ששני List<T> שונים לא משתפים איברים.

למה צריך קונסטרוקטור בכלל — בלי קונסטרוקטור, כל מופע חדש היה נוצר עם ערכי ברירת מחדל ריקים (null/0), ואז היינו צריכים לקבוע כל שדה בנפרד בשורה נפרדת אחרי היצירה — קל לשכוח שדה אחד. קונסטרוקטור מבטיח שכל מופע נוצר עם כל הנתונים ההכרחיים מהרגע הראשון.

למה צריך this — כשפרמטר הקונסטרוקטור נקרא name וגם השדה נקרא Name (או אפילו name באותיות זהות), C# צריכה דרך להבדיל ביניהם. this.Name אומר במפורש “השדה של המופע הנוכחי”, לעומת name הפרמטר הרגיל.

יתרונות

מחלקה מאגדת נתונים קשורים תחת ישות אחת ברורה, במקום משתנים מפוזרים; אפשר ליצור כמה מופעים עצמאיים מאותה תבנית בלי לחזור על ההגדרה; קונסטרוקטור מבטיח שכל מופע נוצר עם נתונים תקינים מההתחלה.

חסרונות

שדות ציבוריים (public) בלי הגנה מאפשרים לכל קוד חיצוני לשנות אותם ישירות, בלי בקרה — נושא שיטופל בשיעור הבא (Properties ו-Access Modifiers); מחלקות רבות מדי לכל דבר קטן עלולות להוסיף מורכבות מיותרת ליחידות פשוטות.

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

• Class = תבנית; Object/Instance = מופע קונקרטי שנוצר ממנה עם new

• כל מופע מחזיק עותק עצמאי משלו של כל השדות — שינוי במופע אחד לא משפיע על אחר

• קונסטרוקטור רץ פעם אחת, ביצירת המופע, ומבטיח אתחול נכון

• this מתייחס למופע הנוכחי; נחוץ במיוחד כשפרמטר ושדה חולקים שם

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

• לבלבל בין ה-Class (התבנית) לבין Object ספציפי (המופע) — “שיניתי את Student” זה עמום, “שיניתי את student1” ברור

• לשכוח this. כשפרמטר ושדה נקראים אותו דבר, ולגרום לשדה להישאר לא מאותחל

• לצפות ששינוי בשדה של מופע אחד ישפיע על מופע אחר — הם עצמאיים לחלוטין

סיכום

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

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

Microsoft Learn — Classes

Microsoft Learn — Constructors


תרגילים

תרגיל 1 — מחלקה ראשונה

המשימה: הגדירו מחלקה Book עם שדות Title ו-Author, וקונסטרוקטור שמקבל את שניהם. צרו שני מופעים שונים והדפיסו את פרטיהם.

בדיקה: שני הספרים מודפסים עם פרטים נכונים ונפרדים, בלי שהם “מתערבבים” זה בזה.

תרגיל 2 — עצמאות בין מופעים

המשימה: צרו שני מופעי Book עם אותו Title בהתחלה. שנו את ה-Title של המופע הראשון בלבד, והדפיסו את שניהם.

בדיקה: רק המופע הראשון השתנה; השני נשאר עם הערך המקורי — הוכחה שהם עצמאיים.


פרויקט מסכם

המשימה: הגדירו מחלקה BankAccount עם שדות Owner (string) ו-Balance (double), וקונסטרוקטור שמקבל שם בעלים ויתרת פתיחה.

דרישות:

  1. קונסטרוקטור שמקבל owner ו-initialBalance, ומאתחל את השדות עם this
  2. יצירת שני מופעי BankAccount שונים עם נתונים שונים
  3. הדפסת פרטי שני החשבונות בפורמט קריא (“בעלים: X, יתרה: Y”)

בדיקה: שני החשבונות מודפסים עם נתונים נכונים ונפרדים לגמרי.

מה בפרק הבא

בפרק הבא — Properties ו-Access Modifiers: איך מגנים על שדות מפני שינוי לא מבוקר מבחוץ, בלי לוותר על הנוחות של גישה ישירה.