الوراثة (دليل البرمجة لـ #C)

الوراثة مع التغليف و تعدد الأشكال واحدة من المواصفات الأساسية الثلاثة (أو ركائز) للبرمجة الكائنية. تمكّنك الوراثة من إنشاء فئات جديدة تعيد استخدام وتوسّع وتعدّل السلوك الذي تم تعريفه في الفئات الأخرى. الفئة المورثة للأعضاء التي تسمى الفئة الأساسية و الفئة التي ترث هذه الأعضاءالفئة المشتقة.

ملاحظة

لا تدعم البنيات مبدأ الوراثة ولكن يمكن أن تقوم بتنفيذ واجهات. لمزيد من المعلومات، راجع الواجهات (ارشادات البرمجة C#).

مفهومياً، الفئة المشتقة عبارة عن تخصيص من الفئة الأساسية. على سبيل المثال، إذا كان لديك فئة أساسية Animal، قد تكون هناك فئة مشتقة Mammal وفئة مشتقة أخرى Reptile. الـ Mammal هو Animal، و الـ Reptile هو Animal، ولكن كلاً من الفئات المشتقة تمثل تخصيص مختلف من الفئة الأساسية.

عندما تقوم بتعريف فئة بأن تكون مشتقة من فئة أخرى، تكسب الفئة المشتقة ضمنياً كل أعضاء الفئة الأساسية باستثناء الدالة الإنشائية والدالة المدمّرة. وبالتالي يمكن للفئة المشتقة إعادة استخدام التعليمات البرمجية الموجودة في الفئة الأساسية دون الحاجة إلى إعادة كتابتها مره أخرى. يمكنك إضافة أعضاء أكثر في الفئة المشتقة. بهذه الطريقة، تكون الفئة المشتقة قد وسّعت وظيفة الفئة الأساسية.

يبين الرسم التوضيحي التالي فئة WorkItem الذي يمثل عنصر العمل في بعض العمليات التجارية. كجميع الفئات، فإنه يعتبر فئة مشتقة من System.Object ويرث كل الأساليب الخاصة به. تضيف فئة WorkItem خمس أعضاء خاصة بها. ويتضمن هذا دالة إنشائية لأن الدوال الإنشائية لا يتم وراثتها. يرث ChangeRequest من WorkItem ويمثل نوع معين من عنصر العمل. ضافت فئة ChangeRequest عضوين جديدين على الأعضاء التي ورثتها من WorkItem و Object. يجب عليها إضافة الدالة الإنشائية الخاصة بها ويجب عليها أيضاً أن تضيف عضو يمكن ChangeRequest من الاقتران بالفئة الأصلية WorkItem التي ينطبق عليها التغيير.

وراثة الفئات

توريث فئة

يوضح المثال التالي كيف يتم التعبير عن علاقات الفئات كما هو موضّح في الرسم التوضيحي السابق في #C. كما يوضح المثال كيفية تجاوز WorkItem الأسلوب الظاهري Object.ToString وكيفية وراثة الفئة ChangeRequest تنفيذ الأساليب من WorkItem.

// WorkItem implicitly inherits from Object class
public class WorkItem
{
    private static int nextID;
    protected int ID { get; set; }
    protected TimeSpan jobLength { get; set; }
    protected string Title { get; set; }
    protected string Description { get; set; }
    // Default constructor
    public WorkItem() 
    {
        ID = 0;
        Title = "Default title";
        Description = "Default description.";
        jobLength = new TimeSpan();
    }
    // Static constructor for static member.
    static WorkItem()
    {
        nextID = 0;
    }
    // Instance constructor.
    public WorkItem( string title, string desc, TimeSpan joblen)
    {
        this.ID = GetNextID();                
        this.Title = title;
        this.Description = desc;
        this.jobLength = joblen;
    }
    protected int GetNextID()
    {
       return ++nextID;
    }
    public void Update(string title, TimeSpan joblen)
    {
        this.Title = title;
        this.jobLength = joblen;
    }

    // Virtual method override.
    public override string ToString()
    {
        return String.Format("{0} - {1}", this.ID, this.Title); 
    }
}

// ChangeRequest derives from WorkItem and adds two of its own members.
public class ChangeRequest : WorkItem
{
    protected int originalItemID {get; set;}
    public ChangeRequest() { }
    public ChangeRequest(string title, string desc, TimeSpan jobLen, int originalID)
    {
        this.ID = GetNextID();
        this.Title = title;
        this.Description = desc;
        this.jobLength = jobLen;
        this.originalItemID = originalID;
    }
}

class Program
{
    static void Main()
    {
        WorkItem item = new WorkItem(                                
                        "Fix Bugs", 
                        "Fix all bugs in my source code branch",
                        new TimeSpan(3, 4, 0, 0));

        ChangeRequest change = new ChangeRequest("Change design of base class",
                                                 "Add members to base class",
                                                 new TimeSpan(4, 0, 0),
                                                 1);

        Console.WriteLine(item.ToString());

        // ChangeRequest inherits WorkItem's override of ToString
        Console.WriteLine(change.ToString()); 

        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
    1 - Fix Bugs
    2 - Change design of base class
*/

الأساليب الظاهرية والأساليب المجردة

عند تصريح أسلوب داخل فئة أساسية كـ virtual يمكن للفئة المشتقةبتجاوز الأسلوب باستخدام تنفيذ خاص بها. إذا تم تعريف العضو داخل الفئة الأساسية كـ abstract يجب تجاوز هذا الأسلوب في أي فئة غير مجردة وترث من الفئة الأساسية مباشرة. إذا كانت الفئة المشتقة نفسها مجردة، فإنها ترث الأعضاء المجردة بدون تنفيذها. الأعضاء الظاهرية والأعضاء المجردة هي أساس "تعدد الأشكال" الذي يعتبر هو ثاني الصفات الأساسية للبرمجة الكائنية. لمزيد من المعلومات، راجع التعدد (إرشادات برمجة C#).

الفئات الأساسية المجردة

يمكنك تعريف الفئة كـ abstract إذا كنت تريد منع إنشاء المثيل المباشر باستخدام الكلمة الأساسية new. في حالة القيام بذلك، يمكن استخدام الفئة فقط إذا تم اشتقاق فئة جديدة منها. يمكن أن تحتوي الفئة المجردة واحد أو أكثر من تواقيع الأساليب والتي يتم تعريفها كـ abstract. تحدد هذي التواقيع المعلمات وقيمة الإرجاع ولكن لا تحدد التطبيق (نص الأسلوب). لا يجب على الفئة المجردة أن تحتوي على أعضاء مجردة; ومع ذلك، إذا احتوت فئة على عضو مجرد، يجب تعريف الفئة نفسها كفئة مجردة. يجب على الفئة المشتقة الغير مجردة توفير التطبيق لأي أسلوب مجرد في الفئة الأساسية المجردة. للمزيد من المعلومات، راجع الفئات المجردة والفئات المغلقة وأعضاء الفئات (دليل البرمجة لـ #C) وتصميم فئة مجردة.

الواجهات

الواجهة عبارة عن نوع مرجع يكون مشابه إلى حد ما الفئة الأساسية المجردة التي تتكون من أعضاء مجردة فقط. عندما تكون الفئة مشتقة من واجهة، يجب عليها أن توفر تطبيق لكافة أعضاء الواجهة. يمكن للفئة من تطبيق واجهات متعددة إلا أنها يجب أن تنحدر مباشرة من فئة أساسية واحدة فقط.

تستخدم الواجهات لتعريف قدرات معينة للفئات التي لا تتضمن بالضرورة علاقة "is a". على سبيل المثال، يمكن تطبيق الواجهة System.IEquatable<T> بواسطة أي فئة أو بنية تمكن التعليمات البرمجية للعميل من تحديد ما إذا كان كائنين من النوع متكافئين أم لا (وكذلك يعرّف النوع التكافؤ). IEquatable<T> لا يتضمن نفس نوع علاقة "is a" الموجودة بين الفئة الأساسية والفئة المشتقة (على سبيل المثال، Mammal "is a"Animal). لمزيد من المعلومات، راجع الواجهات (ارشادات البرمجة C#).

وصول الفئة المشتقة إلى أعضاء الفئة الأساسية

يمكن للفئة المشتقة الوصول إلى الأعضاء العامة والمحمية والداخلية والمحمية الداخلية للفئة الأساسية. على الرغم من أن الفئة المشتقة ترث أعضاء الفئة الأساسية الخاصة، لا يمكن الوصول إلى تلك الأعضاء. مع ذلك، لا تزال تلك الأعضاء الخاصة موجودة في الفئة المشتقة وتقوم بالعمل نفسه الذي تقوم به في الفئة الأساسية. على سبيل المثال، نفرض أن أسلوب فئة أساسية محمي وصل إلى حقل خاص. يجب على الحقل أن يكون موجوداً في الفئة المشتقه حتى يقوم أسلوب الفئة على العمل بشكل صحيح.

منع الاشتقاق

يمكن للفئة منع الفئات الأخرى من الوراثة منها أو أي من أعضائها عن طريق تعريفها أو تعريف العضو كـ sealed. لمزيد من المعلومات، راجع الفئات المجردة والفئات المغلقة وأعضاء الفئات (دليل البرمجة لـ #C).

إخفاء الفئات المشتقة لأعضاء الفئات الأساسية

يمكن للفئة المشتقة أن تخفي أعضاء الفئة الأساسية عن طريق تعريف الأعضاء مع نفس الاسم ونفس التوقيع. يمكن استخدام المعدّل newللإشارة بوضوح إلى أن العضو غير مرغوب به بتجاوز العضو الأساسي. استخدام new غير مطلوب ولكن سيتم إنشاء تحذير برنامج التحويل البرمجي إن لم يتم استخدام new. للمزيد من المعلومات، راجع تعيين الإصدارات مع الكلمات الأساسية override و new (دليل البرمجة لـ #C) ومعرفة وقت استخدام المنع و كلمات أساسية جديدة (إرشادات البرمجة لـ C#).

راجع أيضًا:

المرجع

الفئات والبنيات (دليل البرمجة لـ #C)

class (مرجع #C)

struct (مرجع #C)

المبادئ

دليل البرمجة لـ #C