You are on page 1of 7

‫جامعة ادلب‬

‫كلية الهندسة المعلوماتية‬


‫السنة الثانية‪ -‬مادة برمجة متقدمة ‪1‬‬

‫سبق وأن تحدّثنا عن التعدديّة الشكليّة‪ ،‬وكيف أنّها مفهوم أساس ّ‬


‫ي في البرمجة كائنيّة التوجّه‪ .‬يتمحور مفهوم‬
‫التعدديّة الشكليّة حول أ ّنه يحق للصنف االبن إعادة صياغة تابع (أو خاصيّة) موجود في صنف أب بصورةٍ‬
‫تناسبه أكثر‪ .‬لقد طبّقنا هذا المفهوم قبل قليل وذلك عندما "تجاوز" التابع ‪ MyMethod‬في الصنف‬
‫االبن ‪ ،Child‬التابع ‪ MyMethod‬الموجود في الصنف األب ‪ ،Father‬فأصبح التابع الموجود في‬
‫صا‪ .‬ولكن هذه ليست هي الطريقة المثلى لتنفيذ فكرة التعدديّة الشكلية‪،‬‬
‫ص ً‬
‫االبن يُعبّر عن نفسه بشكل أكثر تخ ّ‬
‫تزودنا سي شارب في الواقع بأسلوب أفضل بكثير لتحقيق هذا المفهوم‪ .‬هل تذكر مثال الضفدع ‪Frog‬‬
‫ّ‬
‫والسمكة ‪ Fish‬والطائر ‪ Bird‬وسلوكيّة االنتقال ‪ Move‬التي يرثونها من الصنف ‪Animal‬؟‬

‫تناولنا هذا المثال البسيط في درس سابق‪ .‬وقد ذكرنا ّ‬


‫أن الصنف ‪ Animal‬هو الصنف األب‬
‫لألصناف ‪ Frog‬و ‪ Fish‬و ‪ Bird‬وهو يحتوي على التابع ‪ Move‬الذي يُعبّر عن سلوكيّة االنتقال‪.‬‬
‫أن ا‬
‫كًّل من األصناف األبناء الثًّلثة تُعبّر بشكل مختلف عن عمليّة االنتقال‪ ،‬لذلك فنحن أمام التعدديّة‬ ‫وبما ّ‬
‫الشكليّة‪ .‬يحتوي البرنامج ‪ oop_6‬على صنف أب ‪ Animal‬يحوي تابعًا وحيدًا اسمه ‪Move‬ـ موسوم‬
‫بالكلمة المحجوزة ‪ virtual‬التي تجعل منه تاب ًعا ظاهرياا يسمح للتوابع األخرى بتجاوزه‪ .‬باإلضافة إلى‬
‫وجود ثًّلثة أصناف أبناء للصنف ‪ Animal‬وهي ‪ Frog‬و ‪ Fish‬و ‪ .Bird‬يحتوي كل صنف من‬
‫األصناف األبناء على التابع ‪ Move‬مع وسم خاص هو ‪ .override‬تسمح هذه الكلمة للتابع في الصنف‬
‫االبن أن "يتجاوز" تعريف نفس التابع في الصنف األب (موسوم بالكلمة ‪ .)virtual‬أعني بكلمة "تجاوز"‬
‫إعادة تعريف التابع بالشكل الذي يناسب الصنف االبن‪ .‬فعند الحديث عن االنتقال‪ ،‬فالذي يناسب‬
‫الضفدع ‪ Frog‬هو القفز‪ ،‬والذي يناسب السمكة ‪ Fish‬هو السباحة‪ ،‬والذي يناسب الطائر ‪ Bird‬بالطبع‬
‫هو الطيران‪ .‬وبالمناسبة ّ‬
‫فإن التابع ‪ ToString‬الموجود في الصنف ‪ Object‬هو تابع ظاهر ّ‬
‫ي (موسوم‬
‫بالكلمة ‪ )virtual‬ليسمح ألي صنف آخر بتجاوزه‪.‬‬

‫إليك اآلن البرنامج ‪:oop_6‬‬

‫‪namespace oop_6‬‬
‫{‬
‫‪class Animal‬‬
‫{‬

‫‪1‬‬ ‫م‪.‬بسمة سراقبي‬


‫جامعة ادلب‬
‫كلية الهندسة المعلوماتية‬
1 ‫ مادة برمجة متقدمة‬-‫السنة الثانية‬
public virtual void Move()
{
Console.WriteLine("Animal:Move General Method");
}
}
class Frog : Animal
{
public override void Move()
{
Console.WriteLine("Frog - Move:jumping 20 cm");
}
}
class Bird : Animal
{
public override void Move()
{
Console.WriteLine("Bird - Move:flying 10 m");
}
}
class Fish : Animal
{
public override void Move()
{
Console.WriteLine("Fish - Move:swimming 1 m");
}
}
class Program
{
static void Main(string[] args)
{
Frog frog = new Frog();
Fish fish = new Fish();
Bird bird = new Bird();
frog.Move();
fish.Move();
bird.Move();
Console.ReadKey();
}
}

2 ‫بسمة سراقبي‬.‫م‬
‫جامعة ادلب‬
‫كلية الهندسة المعلوماتية‬
‫السنة الثانية‪ -‬مادة برمجة متقدمة ‪1‬‬
‫نفّذ البرنامج السابق لتحصل على الخرج التالي‪:‬‬

‫الحظ كيف يُعبّر ك ّل كائن من األصناف األبناء عن التابع ‪ Move‬بالشكل الذي يناسبه‪ .‬وواضح ّ‬
‫أن‬
‫التابع ‪ Move‬الموجود في الصنف األب ‪ Animal‬ال يُستدعى مطل ًقا‪ .‬ولكن في بعض الحاالت قد نرغب‬
‫تجاوز الموجود في الصنف األب إلنجاز بعض المهام ومن ث ّم نتابع العمل ضمن التابع‬
‫أن يُستدعى التابع ال ُم َ‬
‫ال ُمتجا ِوز‪ .‬يمكننا ذلك ببساطة من خًّلل استخدام الكلمة المحجوزة ‪ base‬التي تُشير إلى الصنف األب الذي‬
‫يرث منه االبن‪ .‬الستدعاء التابع ‪ Move‬الموجود في الصنف األب ‪ Animal‬وذلك من خًّلل‬
‫التابع ‪ Move‬الموجود في الصنف ‪ Frog‬أضف العبارة التالية بعد سطر التصريح عن التابع ‪Move‬‬
‫مباشرة ً قبل أي عبارة أخرى‪ ،‬ليصبح هذا التابع على الشكل‪:‬‬

‫)(‪public override void Move‬‬


‫{‬
‫;)(‪base.Move‬‬
‫;)"‪Console.WriteLine("Frog - Move:jumping 20 cm‬‬

‫}‬

‫أعد تنفيذ البرنامج لتحصل على الخرج التالي‪:‬‬

‫انظر كيف استُدعي التابع ‪ Move‬الموجود في الصنف األب ‪ Animal‬ومن ث ّم استُدعي‬


‫التابع ‪ Move‬الموجود في الصنف االبن ‪.Frog‬‬

‫‪3‬‬ ‫م‪.‬بسمة سراقبي‬


‫جامعة ادلب‬
‫كلية الهندسة المعلوماتية‬
‫السنة الثانية‪ -‬مادة برمجة متقدمة ‪1‬‬
‫التحويل بين األنواع‬

‫سنتناول في هذه الفقرة سلو ًكا قد يبدو غريبًا بعض الشيء‪ ،‬ولكنّه مهم وأساس ّ‬
‫ي وسيصادفك في معظم البرامج‬
‫التي تكتبها باستخدام سي شارب‪ .‬أعد البرنامج ‪ oop_6‬إلى حالته األصلية (أي أزل‬
‫العبارة ()‪ .)base.Move‬امسح محتويات التابع ‪ Main‬واستبدلها بالشيفرة التالية‪:‬‬

‫)‪static void Main(string[] args‬‬


‫{‬
‫;)(‪Animal animal = new Frog‬‬
‫;)(‪animal.Move‬‬
‫;)(‪Console.ReadKey‬‬
‫}‬

‫أن الصنف ‪ Animal‬هو‬ ‫العبارة األولى غريبة ً‬


‫قليًّل أليس كذلك؟ في الحقيقة الوضع طبيعي تما ًما‪ ،‬فبما ّ‬
‫مصرح عنه على أ ّنه من النوع ‪( Animal‬في مثالنا‬
‫ّ‬ ‫ي متغيّر‬
‫صنف أب للصنف ‪ Frog‬لذلك فيستطيع أ ّ‬
‫يخزن مرجع إلى كائن من الصنف ‪( Frog‬تذ ّكر ّ‬
‫أن التعبير () ‪new‬‬ ‫هذا هو المتغيّر ‪ )animal‬أن ّ‬
‫‪ Frog‬يولّد مرجع لكائن من الصنف ‪ .)Frog‬نفّذ البرنامج اآلن لتحصل على الخرج التالي‪:‬‬

‫أن الكائن الذي يشير إليه المتغيّر ‪ animal‬هو كائن من‬ ‫ي كفاية لكي يعرف ّ‬ ‫يبدو ّ‬
‫أن برنامجنا ذك ّ‬
‫الصنف ‪ . Frog‬في الحقيقة يحصل هنا تحويل ضمني بين الكائنات‪ ،‬ولكن إذا فعلنا العكس‪ ،‬أي أسندنا‬
‫مرجع لكائن من الصنف ‪ Animal‬إلى متغيّر من النوع ‪ Frog‬فسنحصل على خطأ أثناء ترجمة‬
‫البرنامج‪ .‬امسح محتويات التابع ‪ Main‬واستبدلها بالشيفرة التالية‪:‬‬

‫)‪static void Main(string[] args‬‬


‫{‬
‫;)(‪Animal animal = new Frog‬‬
‫;‪Frog frog = animal‬‬
‫;)(‪Console.ReadKey‬‬

‫}‬

‫‪4‬‬ ‫م‪.‬بسمة سراقبي‬


‫جامعة ادلب‬
‫كلية الهندسة المعلوماتية‬
‫السنة الثانية‪ -‬مادة برمجة متقدمة ‪1‬‬
‫نحاول في السطر الثاني أن نُسند المتغيّر ‪ animal‬من النوع ‪ Animal‬إلى المتغيّر ‪ frog‬من‬
‫النوع ‪ ،Frog‬فنحصل على الخطأ التالي عند محاولة تنفيذ البرنامج‪:‬‬

‫ي من النوع ‪ Animal‬إلى النوع ‪ Frog‬ويقترح علينا‬ ‫يخبرنا هذا الخطأ أنّه ال يمكن التحويل بشكل ضمن ّ‬
‫أن المتغيّر ‪ animal‬يحمل مرجع‬ ‫استخدام عامل التحويل بين األنواع ‪( casting‬هل تذكره؟)‪ .‬رغم ّ‬
‫األول من الشيفرة السابقة) ّإال أنّنا عند محاولتنا‬
‫الكائن من الصنف ‪ Frog‬في حقيقة األمر (انظر السطر ّ‬
‫إسناد المتغيّر ‪ animal‬إلى المتغيّر ‪ frog‬حصلنا على خطأ‪ .‬السبب في ذلك هو أنّه ال يحدث تحويل‬
‫ي بين األنواع ‪ implicit conversion‬وإنّما يتطلّب األمر إجراء تحويل صريح باستخدام عامل‬
‫ضمن ّ‬
‫التحويل بين األنواع‪ .‬إذا استبدلت السطر الثاني من الشيفرة السابقة بالسطر التالي‪ ،‬ستكون األمور على ما‬
‫يرام‪:‬‬

‫)‪static void Main(string[] args‬‬


‫{‬
‫;)(‪Animal animal = new Frog‬‬
‫;‪Frog frog = (Frog)animal‬‬
‫;)(‪Console.ReadKey‬‬

‫}‬

‫الحظ كيف وضعنا عامل التحويل (‪ )Frog‬أمام المتغيّر ‪ .animal‬سيضمن ذلك حدوث التحويل‬
‫ي مشاكل‪.‬‬
‫المطلوب دون أ ّ‬

‫ي ومتى يجب استخدام التحويل الصريح‪ ،‬تذ ّكر منّي‬ ‫لكي تريح نفسك من التفكير متى يحدث التحويل الضمن ّ‬
‫ّ‬
‫ولكن العكس ليس صحي ًحا"‪.‬‬ ‫كثيرا ما يحتوي األب ابنه‪،‬‬
‫القاعدة التالية‪" :‬في حياتنا اليوميّة‪ً ،‬‬

‫أن لهذه القاعدة شواذ في واقعنا‪ ،‬ولكنّها في البرمجة ال تخيب! فالمتغيّر من النوع األب يستطيع استقبال‬
‫أعلم ّ‬
‫ولكن العكس ليس صحيح ما لم نستخدم التحويل الصريح بين األنواع‪.‬‬ ‫ّ‬ ‫أي مرجع لكائن من صنف ابن‪،‬‬

‫‪5‬‬ ‫م‪.‬بسمة سراقبي‬


‫جامعة ادلب‬
‫كلية الهندسة المعلوماتية‬
‫السنة الثانية‪ -‬مادة برمجة متقدمة ‪1‬‬
‫ضا‪ .‬فهناك تحويًّلت تحدث ضمنياا‪،‬‬ ‫تحدث ظاهرة التحويل بين األنواع بالنسبة لألنواع المض ّمنة ‪ built-in‬أي ً‬
‫ي‪ .‬ففي هذه‬ ‫وأخرى تحدث بتد ّخل من المبرمج باستخدام عامل التحويل بين األنواع‪ ،‬ولكن مع فرق جوهر ّ‬
‫ً‬
‫فمثًّل‬ ‫الحالة ليس بالضرورة أن يكون بين األنواع التي تجري عمليّة التحويل فيما بينها أي عًّلقة وراثة‪.‬‬
‫يمكن التحويل ضمنياا بين متغيّر من النوع ‪ int‬إلى آخر من النوع ‪:double‬‬

‫;‪int i = 6‬‬
‫;‪double d = i‬‬

‫أ ّما إذا حاولنا فعل العكس‪:‬‬

‫;‪double d = 6‬‬
‫;‪int i = d‬‬

‫فسنحصل على نفس الخطأ السابق الذي يخبرنا بوجوب استخدام التحويل الصريح بين األنواع‪ .‬يمكن حل‬
‫هذه المشكلة ببساطة باستخدام عامل التحويل (‪ )int‬ووضعه أمام المتغيّر ‪ d‬في السطر الثاني‪:‬‬

‫;‪double d = 6‬‬
‫;‪int i = (int)d‬‬

‫نخبر المترجم هنا أنّنا نريد التحويل فعلياا من ‪ double‬إلى ‪ .int‬ستحتاج إلى مثل هذه التقنيّة دو ًما إذا‬
‫كانت عمليّة التحويل ستؤدّي إلى ضياع في البيانات‪ .‬فالتحويل من ‪ double‬إلى ‪ int‬سيؤدّي إلى ضياع‬
‫القيمة على يمين الفاصلة العشريّة ّ‬
‫ألن المتغيّرات من النوع ‪ int‬ال تقبلها‪ .‬وكذلك األمر عند التحويل‬
‫ألن المتغيّرات من النوع ‪ float‬ذات د ّقة أقل من المتغيّرات من‬ ‫من ‪ float‬إلى ‪ّ double‬‬
‫النوع ‪ ،double‬وهكذا‪.‬‬

‫تمارين داعمة‬
‫تمرين ‪1‬‬

‫عدّل البرنامج ‪ oop_6‬ليعمل كل صنف من األصناف ‪ Frog‬و ‪ Bird‬و ‪ Fish‬على تجاوز‬


‫التابع ‪( ToString‬الموجود في الصنف األب ‪ .)Object‬بحيث عند استدعاء التابع ‪ ToString‬من‬
‫كائن من الصنف ‪ Frog‬نحصل على النص "‪ ،"I am Frog‬وهكذا بالنسبة للصنفين الباقيين ك ّل حسب‬
‫اسمه‪.‬‬

‫‪6‬‬ ‫م‪.‬بسمة سراقبي‬


‫جامعة ادلب‬
‫كلية الهندسة المعلوماتية‬
‫السنة الثانية‪ -‬مادة برمجة متقدمة ‪1‬‬
‫تمرين ‪2‬‬

‫استفد من البرنامج ‪ Lesson08_02‬في إنشاء صنف جديد اسمه ‪ Corolla‬يرث من‬


‫الصنف ‪ .Toyota‬وأضف إلى الصنف الجديد الخاصيّة ‪ ProductionYear‬من النوع ‪ .int‬بعد‬
‫ذلك أنشئ كائ ًنا من الصنف ‪ Corolla‬وحاول إسناد قيم لهذه الخاصيّة‪ ،‬وقرائتها منها‪.‬‬

‫الخالصة‬

‫تعرفنا على مبادئ التعدديّة الشكليّة‬


‫تعرفنا في هذا الدرس على كيفيّة تطبيق الوراثة في سي شارب‪ ،‬كما ّ‬ ‫ّ‬
‫ضا مع التحويل بين األنواع ورأينا‬‫‪ Polymorphism‬وأهميّتها وكيفيّة استثمارها في هذه اللغة‪ .‬وتعاملنا أي ً‬
‫كيف يمكن لمتغيّر من صنف أب أن يحمل مراجع لكائنات من أصناف أبناء‪ .‬تُستَخدم هذه األساليب على‬
‫نحو واسع جداا في مكتبة األصناف األساسيّة‪ ،‬وستحتاجها في العديد من التطبيقات التي تُنشئها‪.‬‬

‫‪7‬‬ ‫م‪.‬بسمة سراقبي‬

You might also like