بسم الله الرحمن الرحيم اقدم اليوم لكم الدرس الثاني بموضوع polymorphism ______________________________________________________________________________ الربط الديناميكي dynamic binding لو قام برنامج باستدعاء تابع(دالة) ظاهري باستخدام مؤشر من نمط صف اساسي إلى غرض تابع إلى صف مشتق ,فإنه سيقوم باختيار التابع المناسب ديناميكيا ً. ونسمي هذه العملية (اي اختيار التابع المناسب اثناء زمن التنفيذ ) بالربط الديناميكي dynamic binding. سنعرض مثال نصممه بالاستعانه بتقنية تعدد الاشكال(الاوجه -الوجهيات ) polymorphism هذا المثال يقوم بطلب المستخدم بادخال قيمة ومن ثم ينظر للقيمة اذا كانت اقل من 10 ينشأ غرض A ويعطيه القيمة اما اذا كان خلاف ذلك سيقوم بانشاء غرض B ويعطيه القيمة الصف(class -الصنف) A يحتوي على دالة طباعة تقوم بعرض القيمة فقط اما الصف B يحتوي على دالة طباعة تقوم بعرض القيمة بعد خصم 5% من القيمة الاصلية.
#include<iostream>using std::cout;using std::cin;using std::endl;#include<new>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 :"<<x<<"it is less than 10"<<endl;}class B:public A{public: B(int=0); print();private: int y;};B::B(int a){ y=a;}B::print(){ cout<<"This Class is B and The value is:"<<y<<" . it is more than 10 and the value aftar the discount is 5% ,Now The value is :"<<y-((5*y)/100)<<endl;}main(){ int value; A *p=NULL; cout<<"Enter The value"; cin>>value; if(value<10) p=new A(value); else p=new B(value); p->print(); return 0;}
_____________________________________________________________________________ نأتي الان إلى موضوع نظري وهو Switch يمكن لنا من خلال تعليمة Switch ان نقوم باستدعاء التوابع من صفوفها على حسب الشرط الذي يتحكم بنوع النمط(الصف-الصنف-الفئة-class) ,وهذه طريقة مجدية , ويمكن ان تكون باستخدام if لكن ! في الانماط المتقدمة والتي تعتمد على مستويات متعدده في البنى الهرمية سيكلف هذا وقتا كثيرا وربما نواجه اخطاء بارسال رسائل غير موجودة داخل الصف , ايضا ربما ينسى المبرمج ان يقوم بعمليات الفحص المطلوبة بشكل صحيح , وكذلك اي تغيير لأي صف من صفوف البنى الهرمية يعتبر تعديلا على عملية switch من جديد وهذا يكلف وقتا كبيرا ويزيد من احتمالية الاخطاء . لذلك اتت تقنية تعدد الاشكال(الاوجه- الوجهيات) polymorphism لتحل هذه المشكلة وتسهل استخدامها داخل البرامج ذات المستويات المتعدده داخل بنية هرمية. ملاحظة :مصظلح "رسالة" مرادف لمصطلح "استدعاء تابع" . ***************************************************************************** سنتكلم اليوم عن موضوع من اهم مواضيع polymorphism تعدد الاشكال. الصفوف المجردة والصفوف الجسدة و التوابع الظاهرية الصافية (الصوافي) pure virtual function التوابع الظاهرية الصافيه (الصوافي) pure virtual function: هذه التوابع هي توابع ظاهرية ولكن تتميز بكلمة صافيه فماذا تعني ؟! تعني كلمة صافيه انها توابع تتواجد في صفوف خاصة تسمى الصفوف المجردة كنماذج فقط ويتم تعريفها في الصفوف المشتقة. والفائدة من هذه التوابع انه في بعض البنى الهرمية نقوم بتعريف صف اساسي ويوجد مثلا دالة طباعة print لا نحتاجها في الصف الاساسي , وانما نحتاجها في الصفوف المشتقة فقط . لذلك نقوم بتعريفها على انها توابع صافيه بإعطائها قيمة pure القيمة pure: لكي نعطي دالة قيمة pure لنجعلها دالة صافيه , نقوم بماسواتها بالصفر اثناء تعريف النموذج مثلا: virtual print()=0 ربما يستبهم الامر على القارء وانا اعلم ذلك لكن يكتفي حاليا في قراءة التعاريف التي ستفهم في مثالنا القادم. الصفوف المجردة: وهي الصفوف التي تحتوي على توابع ظاهرية صافيه, وهذه الصفوف تمثل الارضيه للبنى الهرمية اي انها صف اساسي بمثابة القمة في البنية الهرمية , ولكن هذه الصفوف لا يمكن ان يشتق منها اي غرض والسبب في ذلك انها تحتوي على توابع لا يمكن استدعائها من الصف نفسه لانها غير معرفه فيه الا وهي التوابع الظاهرية الصافيه . الصفوف المجسدة: هي الصفوف التي مرت معنا سابقا , صفوف يمكن اشتقاق اغراض منها , وهي تشتق من الصف المجرد ان وجد . سنعرض لكم الان مثال جيد لشرح التوابع الظاهرية والظاهرية الصافيه والصفوف المجردة والصفوف المشتقة من خلال بنية هرمية مكونه من مستويين . (ملاحظة:في حال استبهام التعاريف ارجوا فهم المثال ومحاولة اعادة تجريبه , ثم العودة مرة اخرى للتعاريف ومقارنتها مع استخدامها داخل المثال . _____________________________________________________________________________
#ifndef PROJECT_H#define PROJECT_Hclass project{public: virtual char *getname()=0; virtual getnum(); virtual print()=0; virtual getSalary(); virtual retired();};#endif
الملف الرأسي لتعريف الصف project
#include<iostream>using namespace std;#include"project.h"project::getnum(){ return 0;}project::getSalary(){ return 0;}project::retired(){ return 0;}
الصف project
#ifndef STUDENT_H#define STUDENT_H#include"project.h"class student:public project{public: student(char * ="",int=0); virtual char *getname(); virtual getnum(); virtual print(); protected: char *name; int number; };#endif
الملف الرأسي لتعريف الصف student
#include<iostream>using namespace std;#include"student.h"student::student(char *nam,int num){ name=nam; number=num;}char *student::getname(){ return name;}student::getnum(){ return number;}student::print(){ cout<<"This Class Is Student Class";}
الصف لـstudent
#ifndef LABOURER_H#define LABOURER_H#include"student.h"class labourer:public student{public: labourer(char * = "",int =0,int=0,int=0); virtual char *getname(); virtual getnum(); virtual print(); virtual getSalary(); virtual retired();private: int salary; int old;};#endif
الملف الرأسي لتعريف الصف labourer
#include<iostream>using namespace std;#include"labourer.h"#include"student.h"labourer::labourer(char *nam,int num,int sal,int ore):student(nam,num){ salary=sal; old=ore;}char *labourer::getname(){ return name;}labourer::getnum(){ return number;}labourer::getSalary(){ return salary;}labourer::retired(){ return old+60;}labourer::print(){ cout<<"This Class Is Labourer"<<endl;}
الصف labourer
#include<iostream>using namespace std;#include"project.h"#include"student.h"#include"labourer.h"void doit(project *pointer){ cout<<"Name is :"<<pointer->getname()<<endl; cout<<"Number is :"<<pointer->getnum()<<endl; cout<<"Salary is :"<<pointer->getSalary()<<endl; cout<<"Retired :"<<pointer->retired()<<endl; pointer->print(); cout<<endl;} main(){ project *p=NULL; student st("Ali",104); labourer la("Ahmad",219,1520,1988); p=&st; doit(p); p=&la; doit(p); return 0;}
___________________________________________________________________________ البرنامج يقوم البرنامج على ثلاثة صفوف الأول هو project وهو صف مجرد لا يمكن ان نشتق اغراض منه لذلك كما قلنا هو يمثل ارضية العمل , فيحتوي على الدوال الموجودة في الصفوف الموجودة بالمستويات الوراثية. نلاحظ تعريف الدالة print والدالة getname على انهما دالتان ظاهريتان صافيتان وذلك عن طريق اعطائهم قيمة pure كما ونلاحظ ظرورة تعريفهم في اول مستويات الوراثة (الصف student ) اما باقي الدوال فهي دوال ظاهرية فقط ونلاحظ انها معرفة في الصف المجرد , وذلك من اجل ارسال اي رسالة (عن طريق مؤشر على الصف الاساسي المجرد ) في صف مشتق ولم تكن موجودة فيه. الصفوف الاخرى student & labourer هذه صفوف مجسدة يمكن اشتقاق اغراض منها كما هو مبين من البرنامج يأخذ الصف student اسم الطالب وكذلك رقمه (اي رقم كمثال فقط ) يأخذ الصفlabourer اسم الموظف ورقمه وراتبه وسنة ولادته. الدوال getname تعيد الاسم getnum تعيد الرقم getSalary تعيد الراتب retired تعيد سنة التقاعد وهي سنة الميلاد زائد 60 دالة print تقوم بطباعة اسم الصف في داخل البرنامج (fig) يتم اشتقاق مؤشر من الصف الاساسي المجرد project ثم اشتقاق اغراض لكلا الصفين student & labourer تم اعطاء المؤشر عنوان غرض الصف student وتم اعطاء المؤشر لدالة doit ثم تمت نفس العملية مع الصف labourer الدالة doit تقوم بطباعة الاسم والرقم والراتب وسنة التقاعد واسم الصف عن طريق استدعاء الدوال بواسطة المؤشر pointer ستكون المخرجات Name Is:Ali Number Is : 104 Salary Is:0 R.S retired:0 This Class Is Student Class Name Is:Ahmad Number Is : 104 Salary Is:0 R.S retired:2048 This Class Is Labourer _________________________________________________________________________ هكذا اكون قد انهيت الدرس الثاني. اتمنى من المولى القدير ان اكون قد وفقت في طرحه مع تمنياتي لكم بالتوفيق ملاحظة: بالنسبة للمصطلحات قمت بكتابة المصطلح على حسب ماورد بأغلب الكتب وايضا كتبة اسمه باللغة الانجليزية .