وراثت

وراثت به یک کلاس اجازه می‌دهد که خصوصیات یا متدهایی را از کلاس دیگر به ارث برد. وراثت مانند رابطه پدر و پسری می‌ماند به طوریکه فرزند خصوصیاتی از قبیل قیافه و رفتار را از پدر خود به ارث برده باشد.

همه متد و خصوصیات کلاس پایه می‌توانند در کلاس مشتق مورد استفاده قرار بگیرند به استثنای اعضاء و متدهای با سطح دسترسی private . همه کلاسها در .NET Framework از کلاس Object ارث می‌برند. مفهوم اصلی وراثت در مثال زیر نشان داده شده است :

   1: using System;
   2: 
   3: class Parent
   4: {
   5:     private string message;
   6: 
   7:     public string Message
   8:     {
   9:         get { return message; }
  10:         set { message = value; }
  11:     }
  12: 
  13:     public void ShowMessage()
  14:     {
  15:         Console.WriteLine(message);
  16:     }
  17: 
  18:     public Parent(string message)
  19:     {
  20:         this.message = message;
  21:     }
  22: }
  23: 
  24: class Child : Parent
  25: {
  26:     public Child(string message) : base(message)
  27:     {
  28: 
  29:     }
  30: }

در این مثال دو کلاس با نامهای Parent و Child تعریف شده است. در این مثال یک عضو را یکبار با سطح دسترسی private (خط 5) و یکبار با سطح دسترسی public (خط 11-7) تعریف کرده‌ایم. سپس یک متد را برای نمایش پیام تعریف کرده‌ایم. یک سازنده در کلاس Parent تعریف شده است که یک آرگومان از نوع رشته قبول می‌کند و یک پیغام نمایش می‌دهد. حال به کلاس Child توجه کنید (خط 24). این کلاس تمام متدها و خاصیت‌های کلاس Parent را به ارث برده است. نحوه ارث بری یک کلاس به صورت زیر است :

class DerivedClass : BaseClass

براحتی می‌توان با قرار دادن یک کالن ( : ) بعد از نام کلاس و سپس نوشتن نام کلاسی که از آن ارث بری می‌شود (کلاس پایه) این کار را انجام داد. در داخل کلاس Child هم یک سازنده ساده وجود دارد که یک آرگومان رشته‌ای قبول می‌کند. وقتی از وراثت در کلاسها استفاده می‌کنیم، هم سازنده کلاس مشتق و هم سازنده پیشفرض کلاس پایه هر دو اجرا می‌شوند. سازنده پیشفرض یک سازنده بدون پارامتر است. اگر برای یک کلاس سازنده‌ای تعریف نکنیم کامپایلر به صورت خودکار یک سازنده برای آن ایجاد می‌کند. اگر هنگام صدا زدن سازنده کلاس مشتق بخواهیم سازنده کلاس پایه را صدا بزنیم باید از کلمه کلیدی base استفاده کنیم. کلمه کلیدی base یک سازنده از کلاس پایه را صدا می زند. قبل از این کلمه کلیدی باید علامت کالن ( : ) را تایپ کنیم.

در مثال بالا به وسیله تأمین مقدار پارامتر message سازنده کلاس مشتق و ارسال آن به داخل پرانتز کلمه کلیدی base ، سازنده معادل آن در کلاس پایه فراخوانی شده و مقدار message را به آن ارسال می‌کند. سازنده کلاس Parent هم این مقدار (مقدار message) را در یک عضو داده‌ای (فیلد) private قرار می‌دهد. می‌توانید کدهایی را به داخل بدنه سازنده Child اضافه کنید تا بعد از سا زنده Parent اجرا شوند. اگر از کلمه کلیدی base استفاده نشود به جای کلاس پایه سازنده پیشفرض فراخوانی می‌شود. اجازه بدهید که اشیایی از کلاسهای Parent و Child بسازیم تا نشان دهیم که چگونه کلاس Child متدها و خواص کلاس Parent را به ارث می‌برد.

   1: class Program
   2: {
   3:     static void Main()
   4:     {
   5:         Parent myParent = new Parent("Message from parent.");
   6:         Child myChild = new Child("Message from child.");
   7: 
   8:         myParent.ShowMessage();
   9: 
  10:         myChild.ShowMessage();
  11: 
  12:         myParent.Message = "Modified message of the parent.";
  13:         myParent.ShowMessage();
  14: 
  15:         myChild.Message = "Modified message of the child.";
  16:         myChild.ShowMessage();
  17: 
  18:         //myChild.message; ERROR: can't access private members of base class
  19:     }
  20: }
Message from parent.
Message from child.
Modified message of the parent.
Modified message of the child.

هر دوشی را با استفاده از سازنده‌های مربوط به خودشان مقدار دهی می‌کنیم. (خطوط 6-5) سپس با استفاده از ارث بری و از طریقشی Child به اعضاء و متدهای کلاس Parent دسترسی می‌یابیم. حتی اگر کلاس Child از کلاس Parent ارث ببرد باز هم اعضای با سطح دسترسی private در کلاس Child قابل دسترسی نیستند (خط 18). سطح دسترسی Protect که در درس آینده توضیح داده خواهد شد به شما اجازه دسترسی به اعضا و متدهای کلاس پایه را می‌دهد. به نکته دیگر توجه کنید. اگر کلاس دیگری بخواهد از کلاس Child ارث بری کند، باز هم تمام متدها و خواص کلاس Child که از کلاس Parent به ارث برده است را به ارث می‌برد.

class GrandChild : Child
{
   //Empty Body
}

این کلاس هیچ چیزی در داخل بدنه ندارد. وقتی کلاس GrandChild را ایجاد می‌کنید و یک خاصیت از کلاس Parent را فراخوانی می‌کنید با خطا مواجه می‌شوید. چون هیچ سازنده‌ای که یک آرگومان رشته‌ای قبول کند در داخل بدنه GrandChild تعریف نشده است بنابراین شما می‌توانید فقط از سازنده پیشفرض یا بدون پارامتر استفاده کنید.

GrandChild myGrandChild = new GrandChild(); 

myGrandChild.Message = "Hello my grandchild!";
myGrandChild.ShowMessage();

وقتی یک کلاس ایجاد می‌کنیم و سازنده GrandChild را فراخوانی می‌کنیم ابتدا سازنده کلاس Parent فراخوانی می‌شود و سپس سازنده Child و در نهایت سازنده GrandChild اجرا می‌شود. برنامه زیر ترتیب اجرای سازنده‌ها را نشان می‌دهد. دوباره کلاسها را برای خوانایی بیشتر در داخل کدهای جدا قرار می‌دهیم.

   1: using System;
   2: 
   3: class Parent
   4: {
   5:     public Parent()
   6:     {
   7:         Console.WriteLine("Parent constructor was called!");
   8:     }
   9: }
  10: 
  11: class Child : Parent
  12: {
  13:     public Child()
  14:     {
  15:         Console.WriteLine("Child constructor was called!");
  16:     }
  17: }
  18: 
  19: class GrandChild : Child
  20: {
  21:     public GrandChild()
  22:     {
  23:         Console.WriteLine("GrandChild constructor was called!");
  24:     }
  25: }
  26: 
  27: class Program
  28: {
  29:     static void Main()
  30:     {
  31:         GrandChild myGrandChild = new GrandChild();
  32:     }
  33: }
Parent constructor was called!
Child constructor was called!
GrandChild constructor was called!