المساعد الشخصي الرقمي

مشاهدة النسخة كاملة : تقنية تعدد الوجهيات (الاوجه - الاشكال) polymorphism



A.N.A time1
01-09-2006, 12:28 AM
بسم الله الرحمن الرحيم


اقدم اليوم لكم أول درس لي في هذا المنتدى وهو درساً في تقنية من أهم تقنيات البرمجة الغرضية التوجيه opject-oriented programming
الا وهو تعدد الاشكال او الاوجه (الوجهيات ) او كما يسمى polymorphism




polymorphism

بالنسبة لي انا لا احب ان اتعلم من دروس لا تحتوي على امثله وتبيين للمفاهيم, لذلك سأعمل من وجهة نظري واقدم درس يحتوي على المفاهيم الخاصة وعرض مثال على هذه المفاهيم

تعتمد تقنية تعدد الوجهيات polymorphism على تقنية الوراثة inheritance و المؤشرات pointers
ونعلم نحن اهمية الصفوف في انشاء اغراض عامه تستخدم في برامج كثيرة حسب حاجتنا لها مما يسهل لنا تصميم البرامج وهذا ماسميى بـ "التعميم" ثم نعلم ان الوراثة inheritance تزيد من مبدأ التعميم حيث اننا نستغل صفوفنا حسب حاجة البرنامج . اما تقنية تعدد الوجهيات (الاشكال - الاوجه) polymorphism تزيد من عمومية الصفوف وتسهل استخدامها خاصه تلك التي ترتبط في بعضها عن طريق وراثه متعددة المستويات.

_______________________________________________________________________

دعونا نتفحص هذا المثال:


#include<iostream>
using std::cout;
using std::endl;

class A
{
public:
A(int=0);
print();
protected:
int x;
};
A::A(int a)
{
x=a;
}
A::print()
{
cout<<"This Class is A and The value of X is :"<<x<<endl;
}

class B:public A
{
public:
B(int=0,int=0);
print();
private:
int y;
};
B::B(int a,int b):A(a)
{
y=b;
}
B::print()
{
cout<<"This Class is B and The value of X+Y is :"<<x+y<<endl;
}
main()
{
A one(1);
B two(5,10);
one.print();
two.print();

A *p=NULL;
p=&one;
p->print();
return 0;
}


من خلال هذا المثال ستكون المخرجات
This Class is A and The value of X is :1
This Class is B and The value of X+Y is :15
This Class is A and The value of X is :1

السطران الاول والثاني من المخرجات واضحان , لكن السطر الثالث لم يفترض به ان يستدعي دالة print في الصف A بل كان من المفروض ان يستدعي دالة print الخاصة للصف B لانه تم اسناد عنوان الغرض الخاص بالصف B إلى المؤشر الخاص بالصف A
لذلك نتوصل هنا إلى قاعدة مهمة جدا ً

استدعاء مؤشر يعتمد على نمط المؤشر وليس الغرض المؤشر عليه.
حسنا الان لو اردنا ان نصحح ماحدث سابقا ً ,فعندها سنتكلم عن التوابع الظاهرية.
تأشير مؤشر صف مشتق على اغراض الصف الاساسي
اي ان نعطي مؤشر من نوع صف مشتق عنوان غرض صف اساسي.
وينتج من خلال هذه المحاولة خطأ لان اغراض الصف الاساسي ليست اغراض للصف المشتق لذلك :
يجب ان نفهم حاليا: بأن أي مؤشر من صف لا يمكن ان يأخذ الا عنوان الصف نفسه او عنوان صف اقل من مستوى في البنية الهرمية (تختلف هذه النظرية عندما نتعلم القسر الادنى) .

محاولة استدعاء توابع الصف المشتق باستخدام مؤشر الى الصف الاساسي
ايضا تحدث خطا.لعدم توفر التوابع في الصف الاساسي




التوابع الظاهرية

للتخلص من استدعاء توابع الصف الاساسي (لا اعني عندما اقول اساسي الصف الأب) واستدعاء التوابع الخاصة بالنمط المسند عنوانه للمؤشر يجب علينا ان نمكن المترجم من فهم اي الدوال المفترض به استدعائها من مستوى البنية الهرمية,على حسب نمط الغرض المسند.
ولتفعيل هذا السلوك يجب علينا تعريف التوابع الاعضاء على انها ظواهر (ظاهرية) ويكون تعريفها في الصف الاساسي.
قاعدتها virtual function
لنرا استخدامها على مثالنا السابق


#include<iostream>
using std::cout;
using std::endl;

class A
{
public:
A(int=0);

virtual print();

protected:
int x;
};
A::A(int a)
{
x=a;
}
A::print()
{
cout<<"This Class is A and The value of X is :"<<x<<endl;
}

class B:public A
{
public:
B(int=0,int=0);
print();
private:
int y;
};
B::B(int a,int b):A(a)
{
y=b;
}
B::print()
{
cout<<"This Class is B and The value of X+Y is :"<<x+y<<endl;
}
main()
{
A one(1);
B two(5,10);
one.print();
two.print();

A *p=NULL;
p=&two;
p->print();
return 0;
}


ستكون المخرجات
This Class is A and The value of X is :1
This Class is B and The value of X+Y is :15
This Class is B and The value of X+Y is :15

هنا نكون قد صححنا السلوك السابق
وهنا نجد ان:
التوابع الظواهر(الظاهرية - الافتراضية) تعيد الدالة التابعه للغرض المسند للمؤشر وليس للنمط المؤشر.
الان ماذا لو قررنا ان نحذف دالة print من صف B ونفذنا البرنامج كما هو :


main()
{
A one(1);
B two(5,10);
one.print();
two.print();

A *p=NULL;
p=&two;
p->print();
return 0;
}

فعندها ستكون المخرجات

This Class is A and The value of X is :1
This Class is A and The value of X is :5
This Class is A and The value of X is :5

بما ان دالة print حذفت من B فقد تم استدعاء دالة print في صف A ولكن بقيمة X التي اعطيت لصف B , هذا السلوك تم بسبب تعريف التابع print على انه ظاهري. ملاحظة:
"يلاحظ المجتهد : بأنه لو حذفنا كلمة virtual من دالة print في صف A فستكون نفس المخرجات " .
هذا صحيح . ولكن وقتها سيكون استدعاء الدالة في الصف الاساسي بغض النظر عن تواجد الدالة بالصف المشتق اما لا.
فلو كان هناك ثلاثة صفوف A,B,C وجميعهما يحتويان على دالة print وتم استدعاء دالة print الخاصة بالصف C بواسطة مؤشر على A فانه سيتم استدعاء دالة print بالصف الاساسي , اما اذا كانت دالة print معرفة على انها ظاهرية وتم استدعاء دالة print الخاصة بالصف C بواسطة مؤشر على A فسيتم استدعاء الدالة الخاصة بـ C بشكل صحيح لكن .؟!
ماذا ان كانت دالة print غير موجودة بصف C
هنا ننظر اذا كانت دالة print بصف B معرفة على انها ظاهرية فسيتم استدعائها .. وان لم تكن كذلك فسيتم استدعاء دالة الصف الاساسي A


إلى هنا اكون قد اكفيت درسي الأول في هذا الصدد
وقريبا سنتكلم عن:
استعمالات اخرى لـ
polymorphism
تعلميات switch ومقارنتها مع polymorphism
الصفوف المجردة والصفوف المجسدة
الصوافي pure virtual
جدول التوابع الظاهرية virtual function table
vtable
المدمرات الظاهرية
القسر الديناميكي واستخدام
dynamic_cast
و
typeid

اتمنى ان اكون وفقت في هذا الدرس , هذا والله أعلم العالمين

سبحانك اللهم لا علم لنا الا ماعلمتنا

تقبلوا تحياتي

ORP
01-09-2006, 04:17 AM
يعطيك العافيه وربنا يجازيك بالخير

wellknownQ8
03-09-2006, 09:51 AM
السلام عليكم ..

ما شاء الله .. موضوع جميل و مهم و قوي. ;)

قرأت الموضوع و جميل منك أن تضع الأمثلة، و هو مفهوم (لكن ليس على المبتدئين أو الهواة).

بارك الله فيك اخي الكريم A.N.A

و شكرا :)

A.N.A time1
03-09-2006, 12:43 PM
اشكرك استاذي wellknownQ8 على مرورك
واشكرك استاذي ORP
طبعا الدرس هو عن تقنية polymorphism وطبعا هذه التقنية للمتقدمين وليس للمبتدئين
والدرس كان بسيط كبداية .. وطبعا انا كتبت الدرس الثاني واتمنى ان يكون مفهوم ايضا وهو درس كثير الدسم:D

هذا واسأل المولى القدير التوفيق لي ولكم
تحياتي

wellknownQ8
31-12-2006, 06:49 AM
يـُرفع لاهميته و فائدته