מחלקות, שדות וקונסטרוקטורים
מה זה?
בשיעורי היסודות ניהלנו תלמיד עם משתנים נפרדים — 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 — Constructors
תרגילים
תרגיל 1 — מחלקה ראשונה
המשימה: הגדירו מחלקה Book עם שדות Title ו-Author, וקונסטרוקטור שמקבל את שניהם. צרו שני מופעים שונים והדפיסו את פרטיהם.
בדיקה: שני הספרים מודפסים עם פרטים נכונים ונפרדים, בלי שהם “מתערבבים” זה בזה.
תרגיל 2 — עצמאות בין מופעים
המשימה: צרו שני מופעי Book עם אותו Title בהתחלה. שנו את ה-Title של המופע הראשון בלבד, והדפיסו את שניהם.
בדיקה: רק המופע הראשון השתנה; השני נשאר עם הערך המקורי — הוכחה שהם עצמאיים.
פרויקט מסכם
המשימה: הגדירו מחלקה BankAccount עם שדות Owner (string) ו-Balance (double), וקונסטרוקטור שמקבל שם בעלים ויתרת פתיחה.
דרישות:
- קונסטרוקטור שמקבל
ownerו-initialBalance, ומאתחל את השדות עםthis - יצירת שני מופעי
BankAccountשונים עם נתונים שונים - הדפסת פרטי שני החשבונות בפורמט קריא (“בעלים: X, יתרה: Y”)
בדיקה: שני החשבונות מודפסים עם נתונים נכונים ונפרדים לגמרי.
מה בפרק הבא
בפרק הבא — Properties ו-Access Modifiers: איך מגנים על שדות מפני שינוי לא מבוקר מבחוץ, בלי לוותר על הנוחות של גישה ישירה.