الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

الوراثة ببساطة

بدأه Robatic في 2 أبريل 2011 · 6 رد · 6,562 مشاهدة · في Microsoft Visual C#.NET
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم ورحمة الله وبركاته

قد يكون الموضوع مكرر أو قد يكون هناك بعض الإخوة أو الإخوات ممن تشبعوا بالـ Inheritance في ضل لغات برمجية أخرى مثل C++ أو Java. ولكن صدقوني أنه سيتم التطرق لبعض الأشياء التي قد تكون غائبة عن البعض أو التي لها علاقة بالـ Compiler . سيتم التطرق للمواضيع التالية بشكل موجز وبسيط، فبسم الله نبدأ:

أولا : Inheritance

يمكن لـ Class أن يرث Class آخر وذلك لتمديد أو تخصيص الـ Class الأصل. وراثة Class معين من شأنه إتاحة الفرصة لإستخدام وظائف هذا الـ Class بدل من بنايته من الصفر. لا يمكن لـ Class أن يرث أكثر من Class واحد فقط ولكن يمكن أن يتم وراثة هذا الـ Class من عدة Classes. يمكن لـ Class أن يرث عدة interfaces. دعونا نأخذ المثال التالي :

    // This will be our baseclass

    public class Vehicle
    {
        public int MaxSpeed;
        public int Passaengers;
    }

سنقوم بتعريف كلا من Car و Truck حيث سيرث كل منهما Vehicle وذلك من شأنه إعطاء كلا من Car و Truck كل ما هو موجود في Vehicle بالإضافة إلى كل ما هو جديد في كل منهما.

    public class Vehicle
    {
        public int MaxSpeed;
        public int Passaengers;
    }

    public class Car : Vehicle  // inherits from Vehicle
    {
        public bool IsHatchBack;
    }

    public class Truck : Vehicle  // inherits from Vehicle
    {
        public double MaxLoad;
    }

    // Main Program

    class Program
    {
        static void Main(string[] args)
        {
            // New C# 3.0 initialzation of objects
            Car carOb = new Car() { MaxSpeed = 160, Passaengers = 4, IsHatchBack = true };

            // Old scholl initialization of objects
            Truck truckOb = new Truck();
            truckOb.MaxSpeed = 140;
            truckOb.Passaengers = 2;
            truckOb.MaxLoad = 500;

            Console.WriteLine("Car");
            Console.WriteLine("Maximum Speed: {0} kmph", carOb.MaxSpeed);
            Console.WriteLine("Passemgers: {0}", carOb.Passaengers);
            Console.WriteLine("Has hatch back: {0}", carOb.IsHatchBack ? "Yes" : "No");

            Console.WriteLine(new string('-', 30));

            Console.WriteLine("Truck");
            Console.WriteLine("Maximum Speed: {0} kmph", truckOb.MaxSpeed);
            Console.WriteLine("Passemgers: {0}", truckOb.Passaengers);
            Console.WriteLine("Maximum Load: {0:0.00} kg", truckOb.MaxLoad);
        }
    }

نلاحظ أن كلا من الـ Subclasses يرثون خاصيتين من الـ Baseclass وهي MaxSpeed & Paseengers . قد يتم تسمية الـ Subclass بإسم Derived Class وأيضا الـ Baseclass بالإسم Superclass. إلى الآن لا يوجد شيء معقد بل العملية مباشرة جدا.

ثانيا : Polymorphism

الـ Polymorphism أو تعدد الأشكال هي عبارة عن ما يسمى بـ Is A "هو"، أي أن Subclass Reference is a Baseclass reference ولكن العكس غير صحيح. بمعنى آخر، يمكن لـ Reference من نوع Baseclass (Vehicle) أن يشير إلى Object من نوع Subclass (Car or Truck).

Car carOb; // This is a Car reference

new Car(); // This is a Car object store somewhere in the heap

// Since a Subclass object is a baseclass object (Always true), then a Car is a Vehicle
// So the following line will not produce a syntax error

Vehicle ob = new Car();  // Always true

// But the converse is not true

Car ob = new Vehicle() // A syntax error

دعونا نضيف Static Method للـ Main Program حيث أنها تأخذ Parameter من نوع Vehicle ثم تقوم بطباعة السرعة القصوى.

    class Program
    {
        static void Main(string[] args)
        {
            // New C# 3.0 initialzation of objects
            Car carOb = new Car() { MaxSpeed = 160, Passaengers = 4, IsHatchBack = true };

            Display(carOb);
        }

        public static void Display(Vehicle ob)
        {
            Console.WriteLine("Max Speed: {0}", ob.MaxSpeed);
        }
    }

ماذا لو قمنا بتعديل Display بحيث أنها تقوم بطباعة ما إذا كانت السيارة Hatch Back أو لا.

     public static void Display(Vehicle ob)
     {
     	Console.WriteLine("Has Hatch Back: {0}", ob.IsHatchBack ? "Yes" : "No");
     }

عندم عمل Compile للكود أعلاه سيظهر خطأ وهو عدم وجود تعريف لـ IsHatchBack في Vehicle. على الرغم من أن الـ Object فعليا من نوع Car وهو يحوي تعريف لـ IsHatchBack إلا أن الـ Reference (ob in our case) هو من نوع Vehicle ولا يحوي تعريف لـ IsHatchBack وهذا ما يجعل الـ Compiler يعترض بإظهار رسالة الخطأ. لكي نصل إلى IsHatchBack ينبغي علينا أن نقوم بما يعرف بالـ Downcasting.

ثالثا : Downcasting

هي ما تعرف بعملية إنشاء Subclass Reference عن طريق Baseclass Reference والعملية العكسية لذلك هي Upcasting حيث أنها تحدث بشكل ضمني وذلك وفقا لقاعدة Is A (which is always true). دعونا نأخذ الأمثلة التالية:

     class Program
    {
        static void Main(string[] args)
        {
            // New C# 3.0 initialzation of objects
            Car carOb = new Car() { MaxSpeed = 160, Passaengers = 4, IsHatchBack = true };

            Vehicle v = carOb; // OK (Implicit Upcastnig)
            Console.WriteLine(v.MaxSpeed);
            Console.WriteLine(v.Passaengers);

            // Variable 'v' still reference the same 'Car' object as variable 'carOb', if you need profe read on
            Console.WriteLine("Is 'v' and 'carOb' reference the same objec ? {0}", v == carOb);

            // Downcasting

            Car newCarOb = (Car)v;
            Console.WriteLine("Has Hatch Back? {0}", newCarOb.IsHatchBack ? "Yes" : "No");

            Console.WriteLine(newCarOb == carOb);
            Console.WriteLine(newCarOb == v);
        }
    }

في عملية الـ Upcasting يتم التأثير فقط على الـ References وليس الـ Actual Object على عكس عملية الـ Downcasting والتي تتطلب تغيير ظاهر Explicit Casting لأن هناك خطاء محتمل قد يحدث في مرحلة الـ Runtime.

رابعا: The “as” and “is” operators

الـ as Operator تستخدم في عملية الـ Downcasting والتي تعطي null في حالة فشل العملية. أما الـ is Operator فهي تستخدم في التحقق ما إذا كانت عملية الـ Downcasting ستنجح أم لا، بمعنى آخر التحقق من أن object معينة ترث Class معين أو تطبق Interface معينة.

    class Program
    {
        static void Main(string[] args)
        {
            // as operator

            Vehicle v = new Vehicle();
            v.MaxSpeed = 160;

            Car c = v as Car;   // c is null, no exception is thrown.

            Car c2 = (Car)v;    // this line will throw 'InvalidCastException

            // is operator

            if (v is Car)
                Console.WriteLine(((Car)v).MaxSpeed);
        }
    }

ملاحظة: عندما تستخدم as operator مع متغير من نوع int يقوم الـ compiler بعرض رسالة خطاء، لماذا ؟

خامسا : Virtual Methods Members

عندما يشار إلى method بأنها virtual فهذا من شأنه إعطاء القدره لكل derived class أن يقوم بإعادة تعريف override هذه الـ method. ينطبق ذلك على كل من methods, properties, indexers, and events. دعونا تعديل تعريف كل من Vehicle, Car , and truck.

    public class Vehicle
    {
        public int MaxSpeed;
        public int Passaengers;

        public virtual string Info()    // this method is marked as virtual
        {
            return string.Format("Maximum Speed: {0} kmph, Passengers: {1}", MaxSpeed, Passaengers);
        }
    }

    public class Car : Vehicle  // inherits from Vehicle
    {
        public bool IsHatchBack;

        public override string Info()   // overriding base virtual method
        {
            return string.Format("Maximum Speed: {0} kmph, Passengers: {1}, Hatch Back: {2}", 
                MaxSpeed, Passaengers, IsHatchBack);
        }
    }

    public class Truck : Vehicle  // inherits from Vehicle
    {
        public double MaxLoad;

        public override string Info()   // overriding base virtual method
        {
            return string.Format("Maximum Speed: {0} kmph, Passengers: {1}, Maximum Load: {2:0.00} kg",
                MaxSpeed, Passaengers, MaxLoad);
        }
    }

// -------------------- Main Program

    class Program
    {
        static void Main(string[] args)
        {
            Vehicle v = new Vehicle() { MaxSpeed = 250, Passaengers = 2 };
            Car c = new Car() { MaxSpeed = 180, Passaengers = 4, IsHatchBack = true };
            Truck t = new Truck() { MaxSpeed = 160, Passaengers = 2, MaxLoad = 512.215648 };

            DisplayInfo(v);
            DisplayInfo(c);     // Implicit Downcasting
            DisplayInfo(t);     // Implicit Downcasting
        }

        public static void DisplayInfo(Vehicle ob) // 'is a' makes your life a lot more easier
        {
            Console.WriteLine(ob.Info());
        }
    }

سادسا : Abstract Classes and Abstract Members

هي عبارة عن Classes مجردة تحوي بداخلها Abstract Members وهي تشبة الـ Virtual Method ولكن الفرق الوحيد هو أنها لا تحتوي على تعريف، فقط مجرد declaration. لا يمكننا إنشاء object من أي Abstract Class.

    public class MyConcreteClass : MyAbstactClass
    {
        public override string StringProperty
        {
            get { return "Overriden abstract property"; }
        }

        public override void VoidMethod()
        {
            Console.WriteLine("Overriden abstract method");
        }
    }

// -------------------- Main Program

    class Program
    {
        static void Main(string[] args)
        {
            MyConcreteClass ob = new MyConcreteClass();
            Console.WriteLine(ob.StringProperty);
            ob.VoidMethod();
        }
    }

سابعا : Hiding Inherited Members

قد يكون هناك members متطابقين في كل من الـ Baseclass والـ Subclass

public BaseClass {
	public int x;
}

public SubClass : BaseClass {
	public int x;
}

نقول على المتغير x الموجود في SubClass أنه يخفي Hide المتغير x والموجود في BaseClass. عادة يحدث ذلك عن طريق الخطأ ولهذا السبب يقوم الـ compiler بتوليد رسالة تحذيرية ولكنه في الأخير يقوم بحل هذا الغموض (Which x?) عن طريق نوع الـ Reference، بمعنى آخر لو كان الـ Reference من نوع BaseClass فإنه سيتخدم BaseClass.x والعكس صحيح. في النادر قد تريد أن تقوم بعمل hide لأحد الـ Members الموجودة في الـ Baseclass بصورة متعمدة، في هذه الحالة قم بإستخدام الـ new modifier حيث أن الغرض منها هو إخبار الـ Compiler أو من سوف يقوم بإستخدام الـ code من بعدك أن هذا الـ hide ليس عن طريق الخطأ. لاحظ أن لغة C# تقوم بـ overload للكلمة new keyword حيث أن وظيفتها تتغير على حسب المحتوى الذي يحويها.

سؤال : ما الفرق بين override و new ؟ للإجابة على هذا السؤال دعونا نأخذ المثال التالي:

    public class BaseClass
    {
        public virtual void Foo() { Console.WriteLine("BaseClass.Foo()"); }
    }

    public class Overrider : BaseClass
    {
        public override void Foo()
        {
            Console.WriteLine("Overrider.Foo()");
        }
    }

    public class Hider : BaseClass
    {
        public new void Foo() { Console.WriteLine("Hider.Foo()"); }
    }

// -------------------------- Main Program

    class Program
    {
        static void Main(string[] args)
        {
            Overrider overrider = new Overrider();
            BaseClass b1 = overrider;

            overrider.Foo();                // Overrider.Foo()
            b1.Foo();                       // Overrider.Foo()

            Hider hider = new Hider();
            BaseClass b2 = hider;

            hider.Foo();                    // Hider.Foo()
            b2.Foo();                       // BaseClass.Foo() "Since b2 is a reference of type BaseClass"
        }
    }

ثامنا : The base Keyword

وظيفتها تشبه إلى حد كبير وظيفة الـ this keyword وهي تستخدم لغرضين، الأول هو إستدعاء الـ overridden members من خلال الـ Subclass والثاني هو إستددعاء الـ Constructor الخاص بالـ Baseclass من خلال الـ Subclass. نفس المبداء ينطبق على الـ Hidden members.

    public class BaseClass
    {
        public virtual void Foo() { Console.WriteLine("BaseClass.Foo()"); }
    }

    public class Overrider : BaseClass
    {
        public override void Foo()
        {
            base.Foo();         // Will print 'BaseClass.Foo()'
            Console.WriteLine("Overrider.Foo()");
        }
    }

تاسعا : Constructors and Inheritance

ينبغي على اللـ SubClass أن يقوم بتعريف Constructor(s) خاصة به حيث أنه لا يتم توريث الـ Baseclass Constructor(s)، لو حاولت compile الكود التالي ستظهر هناك رسالة خطأ (على الرغم من أن الخطأ ليس له علاقة بغياب الـ Constructor الخاص بالـ Subclass)

    public class BaseClass
    {
        int x;
        public BaseClass(int x) { this.x = x; }
    }

    public class SubClass : BaseClass
    {
    }

هنالك طريقتين للتخلص من الخطأ الأولى عن طريق تعريف Constructor في الـ Subclass ثم إستخدام الكلمة المحجوزة base لإستعداء وتمرير قيمة x إلى الـ BaseClass Constructor. والثانية سأتطرق لها في النقطة التالية :

    public class BaseClass
    {
        int x;
        public BaseClass(int x) { this.x = x; }
    }

    public class SubClass : BaseClass
    {
        public SubClass(int x) : base(x) // Passing this.Constructor argument to base.Constructor
        { }
    }

ينبغي الإشارة إلى أن ترتيب الإستدعاء في الـ Constructors يبداء من الـ Baseclass ثم الـ Subclass.

عاشرا: Implicit calling of the parameterless base class constructor

بشكل إفتراضي، إذا لم تقم بتعريف constructor للـ class الذي قمت بإنشائة، سيقوم الـ Compiler بتعريف Parameterless constructor لك. وهذا هو سبب المشلكة الفعلي في النقظة السابقة، وعلى ضوء ذلك يمكننا إعادة حلها بالشكل التالي:

    public class BaseClass
    {
        int x;

        public BaseClass() { } // Explicit parameterless constructor definition
        public BaseClass(int x) { this.x = x; }
    }

    public class SubClass : BaseClass
    {
    }

أتمنى للجميع التوفيق والنجاح

تم تعديل هذه المشاركة بواسطة Robatic في 2 أبريل 2011 في 01:04

3
#2

موضوع رائع جدا بارك الله فيك

معلومات قيمة و مفيدة

#3

ما شاء الله عليك أخي

دائما تميز وابداع

سؤال هل هذا الكلام ينطبق على كل اللغات في بيئة .net

وهل هذا الكلام يختلف عن لغة c# بما يخص برمجة المواقع يعني بتقنية asp.net

شكرا

الله أكبر الله أكبر الله أكبر لآ إله إلا الله الله أكبر الله أكبر ولله الحمد

#4
KV2010 كتب:

ما شاء الله عليك أخي

دائما تميز وابداع

سؤال هل هذا الكلام ينطبق على كل اللغات في بيئة .net

وهل هذا الكلام يختلف عن لغة c# بما يخص برمجة المواقع يعني بتقنية asp.net

شكرا

هذه الأساسيات هي نفسها في كل التقنيات التي تنطوي تحت مظلة الـNET. (مع اختلاف في الـsyntax طبعاً في حالة VB.NET واللغات الأخرى).

1
#5

good work

#6
اقتباس
هذه الأساسيات هي نفسها في كل التقنيات التي تنطوي تحت مظلة الـNET. (مع اختلاف في الـsyntax طبعاً في حالة VB.NET واللغات الأخرى).

شكرا أخي الكريم على الإجابة

الله أكبر الله أكبر الله أكبر لآ إله إلا الله الله أكبر الله أكبر ولله الحمد

#7

مشكور جدا أخي الكريم معلومات قيمة

قل لمن يحمل هما ****** إن همــــا لا يدوم
:rolleyes: :rolleyes: :clapping: :rolleyes: :rolleyes:

مثلا تفنى المسـرة ***** هكذا تفنى الهموم

مواضيع مشابهة