מדריך C# – תכנות מונחה עצמים: רב צורתיות – Polymorphism
פולימורפיזם (רב-צורתיות) הינה היכולת לתת מימוש שונה לאותה הפונקציה במחלקה היורשת כך שבזמן ריצה תופעל הפונקציה שמתאימה לטיפוס האובייקט. גם בנושא זה דנו במאמר המבוא ל- OOP ובמאמר זה נלמד איך לממש זאת. פולימורפיזם מתבסס על הורשה ואין פולימורפיזם ללא הורשה.
מימוש Polymorphism
בכדי לממש פולימורפיזם יש תחילה להגדיר את הפונקציה במחלקת הבסיס כוירטואלית (virtual) ובמחלקה היורשת להגדיר לדרוס אותה באמצעות override. לאחר מכן יש ליצור ייחוס ממחלקת הבסיס שיצביע על אובייקט מסוג המחלקה היורשת ולהפעיל את הפונקציה.
שימו לב שלא ניתן לבצע override אם הפונקציה במחלקת הבסיס לא הוגדרה ב- virtual ובדריסה רגילה, כפי שלמדנו בפרק ההורשה (באמצעות new) לא תופעל הפונקציה המתאימה לאובייקט.
בנוסף חשוב לדעת שפונקציה שביצענו ל- override היא גם וירטואלית לדור הבא שירש אותה.
בדוגמא הבאה תופעל הפונקציה Print השייכת למחלקה היורשת:
class Program
{
static void Main(string[] args)
{
Base b = new Derived();
Console.WriteLine(b.Print());
}
}
class Base
{
public int X { get; set; }
public virtual string Print()
{
return "Base print";
}
}
class Derived : Base
{
public int Y { get; set; }
public override string Print()
{
return "Derived print";
}
}
גישה לאובייקט
כאשר הייחוס הוא מסוג הבסיס והאובייקט הוא מסוג יורש לא ניתן לגשת לאלמנטים של היורש, אם ננסה לעשות זאת תתקבל שגיאת קומפילציה. אם בכל זאת נרצה לעשות נצטרך להצביע על האובייקט עם ייחוס המתאים לאובייקט (מסוג היורש).
לדוגמא אם ננסה לבצע זאת נקבל שגיאת קומפילציה:
b.Y = 10;
נצטרך לבצע זאת כך:
Derived d = (Derived)b;
d.Y = 10;
או בקיצור:
((Derived)b).Y = 10;
שימושים של Polymorphism:
- יצירת מערך הטרוגני – ניתן ליצור מערך מסוג הבסיס כך שכל איבר במערך יהיה אובייקט מסוג יורש וכאשר נרוץ על המערך ונפעיל את הפונקציה, תופעל הפונקציה המתאימה לאובייקט. היתרון הוא שלא נצטרך לבדוק עבור כל איבר מה הטיפוס שלו.
- קבלה לפונקציה – ניתן לבנות פונקציה המקבלת משתנה מסוג בסיס ולשלוח אליה בכל פעם אובייקט מסוג אחר היורש את הבסיס.
דוגמא מלאה ל- Polymorphism:
להלן דוגמא מלאה הכוללת מימוש של פולימורפיזם בהורשה עם מספר דורות ושימושים של פולימורפיזם.
תרשים המחלקות:
class Person
{
//Fields:
string firstName;
string lastName;
//Properties:
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
public string LastName
{
get { return lastName; }
set { lastName = value; }
}
//C'tors:
public Person()
: this("", "")
{
}
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
//Methods:
public virtual string Print()
{
return string.Format("Name: {0} {1}",
FirstName, LastName);
}
}
class Student : Person
{
//Fields:
private int[] grades;
//Properties:
public int[] Grades
{
get { return grades; }
set { grades = value; }
}
//C'tors:
public Student()
{
Grades = new int[5];
}
public Student(string fName, string lName, int[] grades)
: base(fName, lName)
{
Grades = grades;
}
//Methods:
public override string Print()
{
string str = base.Print() + "\nGrades:\t";
foreach (int g in Grades)
str += g + ";";
return str;
}
}
class Employee : Person
{
//Fields:
private double salary;
//Properties:
public double Salary
{
get { return salary; }
set
{
if (value < 0)
throw new Exception("Illegal salary");
salary = value;
}
}
//C'tors:
public Employee()
{
Salary = 0;
}
public Employee(string fName, string lName, double salary)
: base(fName, lName)
{
Salary = salary;
}
//Methods:
public override string Print()
{
return base.Print() +
string.Format("\nSalary: {0}", Salary);
}
}
class Manager : Employee
{
//Fields:
private double bonus;
//Properties:
public double Bonus
{
get { return bonus; }
set
{
if (value < 0)
throw new Exception("Illegal bonus");
bonus = value;
}
}
//C'tors:
public Manager()
{
Bonus = 0;
}
public Manager(string fName, string lName,
double salary, double bonus)
: base(fName, lName, salary)
{
Bonus = bonus;
}
//Methods:
public override string Print()
{
return base.Print() +
string.Format("\tBonus: {0}", Bonus);
}
}
class Program
{
static void Main(string[] args)
{
Person[] pArr = new Person[5];
pArr[0] = new Person("A","AA");
pArr[1] = new Employee("B", "BB",10000);
pArr[2] = new Student("C", "CC",new int[]{80,100,90});
pArr[3] = new Person("D", "DD");
pArr[4] = new Manager("E", "EE",20000,5000);
foreach (Person p in pArr)
{
Console.WriteLine("\n"+p.GetType().Name);
Console.WriteLine(p.Print());
}
Person p1 = new Person("Avi", "Levi");
Manager m1 = new Manager("Lior", "Zamir", 20000,5000);
Console.WriteLine("\n---------\nPrinting Person:");
PrintPerson(p1);
Console.WriteLine("\nPrinting Manager:");
PrintPerson(m1);
}
static void PrintPerson(Person p)
{
Console.WriteLine(p.Print());
}
}
פלט התוכנית:
תגובות בפייסבוק