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

تقنية تعدد الوجهيات (الاوجه - الاشكال) polymorphism الدرس الثاني

مغلق
بدأه time1 في 3 سبتمبر 2006 · 8 رد · 6,053 مشاهدة · في المواضيع والدروس
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

بسم الله الرحمن الرحيم

اقدم اليوم لكم الدرس الثاني بموضوع 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_H
class 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

_________________________________________________________________________

هكذا اكون قد انهيت الدرس الثاني.

اتمنى من المولى القدير ان اكون قد وفقت في طرحه

مع تمنياتي لكم بالتوفيق

ملاحظة: بالنسبة للمصطلحات قمت بكتابة المصطلح على حسب ماورد بأغلب الكتب وايضا كتبة اسمه باللغة الانجليزية .

:)

llback.jpg

اشهد ان لا إله إلا الله وان محمدا ً رسول الله

#2

الله يعطيك العافيه ... ما شالله عليك ..

لا يكون لك فكر بالنسبه للمصطلحات .. اعتقد انه طلاب البرمجه فاهمين شو بتقصد ...

بانتظار المزيد منك :)

Success Is A Journey Not A Destination

#3

وفقك الله للمزيد... درس مفيد جدّاً ولا غنى عنه.

#4

Jordan اتمنى ذلك .. فلا اعتقد انه يوجد ترجمة للمصطلحات اكثر من كذا

اسماعيل ابراهيم : شرف كبير لي استاذي ان اجد ردك في موضوعي

وقريبا ان شاء الله الدرس الاخير

llback.jpg

اشهد ان لا إله إلا الله وان محمدا ً رسول الله

#5

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

جزاك الله خيراً أخي time1 ,,, والله لقد استمتعت بالدرس كثيراً ,,,

وبعد أذنك اخي time1 سوف اسوق مثال اخر يوضح ماهية الموضوع ,,,

هناك قاعدة عند مبرمجي OOP تقول:

قم بجعل الفئة مجردة لابعد الحدود ,,,, !!!!!!!!!!!

لفهم اعمق للعبارة السابقة دعنا نستعرض معاً سيناريو المشروع التالي :

نحن الان بصدد بناء مشروع يقوم بتسجيل الموظفين لدينا في الشركة , حيث ستحفظ بيانات الموظفين في ملفات نصية وملفات XML .

الى هنا انتهى السيناريو ,, !! ولكن يا كيف يا ترى سوف نقوم ببناء الفئات ؟؟؟

ان بناء فئات اي مشروع تنقسم الى قسمين :

الفئات المجردة ( طبعاً لا اقصد بها ال Abstract Classes ) وانما اقصد بكلمة مجردة انه لا توجد علاقة ما بين تلك الفئات والبرنامج ,, !!!!!!!

للتوضيح اكثر دعنا نفصل الفئات الاساسية التي سيعتمد عليها البرنامج السابق الذكر :-

الفئات هي ....

TextFile Class
XmlFile Class
Employee  Class

كما تلاحظ انها ثلاث فئات اثنتان منها لا توجد لهما علاقة بالبرنامج لا من قريب ولا من بعيد وهما ال TextFile Class و XmlFile Class والفئة الوحيدة التي لها علاقة قوية جداً بالبرنامج هي ال Employee Class ,, !!! قد يستعجب احدكم هذا الكلام !! ولذلك سوف افصل اكثر ,,,

اذا قلت لك قم بتوظيف الفئة Employee Class في اي برنامج اخر غير البرنامج السابق الذكر ,, !!

لا تحتار يا عزيزي من الصعب توظيفها في اي برنامج اخر لانها صنعت خصيصاً للبرنامج السابق ,, !!

اي انها صنعت لكي تقوم بخدمة البرنامج السابق دون سواه ,,!!

ولكن ماهو الحال يا ترى بالنسبة لكل من ال TextFile Class و XmlFile Class ,, !!

الفئات السابقة الذكر من السهل توظيفها في اي برنامج اخر لانها اساساً لم تصنع من اجل خدمة برنامج تسجيل الموظفين , وانما صنعت فقط من اجل التعامل مع الملفات واستدعائها عند الحاجة اليها ,, !!

وهذا ما قصدته من كلمة الفئات المجردة اي انها مستقلة بذاتها تماماً عن هيكلية البرنامج الذي نعمل عليه ,, وابسط مثال لمثل هذه الفئات هي ال FrameWork الخاصة بمنصة ال Dot Net ,, فكل الفئات الموجودة فيها ماهي الا فئات مجردة صنعت من اجل الاستخدمات العامة في كل البرامج ,,

من الكلام السابق يتضح ان الفئات في اي مشروع تنقسم الى قسمين :

1 - فئات تقوم بخدمة البرنامج الذي تعمل وترتبط به ارتباطاً وثيقاً .

2 - فئات عامة ليس لها دخل بالبرنامج الذي تقوم ببنائه وتستطيع اعادة استخدامها في اي مشروع أخر .

ولتطبيق المفهوم سابق الذكر والمفهوم المسمى polymorphism او تعدد الاشكال الذي ذكره الاخ العزيز time1 اليك التالي :-

المشروع يتكون من الفئات التالية :

1 - Employee Class :-

هي الفئة المسئولة عن تسجيل بيانات الموظفين وحفظها اما في ملفات نصية او في ملفات XML .

بواسطةال Methode التي تسمى AddNewEmployee .

2 - TextFile Class :-

هي الفئة المسئولة عن حفظ اي بيانات نريدها في ملفات نصية .

3 - XmlFile Class :-

هي الفئة المسئولة عن حفظ اي بيانات نريدها في ملفات XML .

الى هنا انتهينا من بناء الفئات وبقي لدينا مناقشة فكرة عمل ال Methode المسماة AddNewEmployee فهذه ال Methode عملها الاساسي هو حفظ البيانات اما في ملفات نصية او XML ,, !!

فكيف يا ترى سوف تقوم بعمل ذلك ؟؟

سيقول احدهم سوف اضع متغير مثلا Int وعلى ضوء قيمة ذلك المتغير سوف اقوم باللازم كهذا مثلاً :

void AddNewEmployee(int x , char* FileName){

	switch(x){

	case 0:

		TextFile txt;
		txt.SaveFile(FileName);
		break;

	case 1:

			XmlFile xml;
			xml.SaveFile(FileName);

	};

	};

اذا كان هذا هو تفكيرك فهو تفكير سليم ولكن ليس مائة في المائة لماذا يا ترى ؟؟؟

لانه لو طلب منك اضافة انواع ملفات جديدة كملفات HTML و XHTML .... الخ , فانك سوف تضطر الى الدخول مرة اخرى الى ال Methode المسماة AddNewEmployee واضافة المزيد من جمل التفرع !!

حسنا ما الحل ,,, ؟؟

الحال هو استخدام تقنية ال polymorphism او تعدد الاشكال التي ذكرها اخونا time1 حيث تنص هذه التقنية على الاتي :

اي Methode تأخذ مؤشراً لفئة تعتبر هي الفئة الام ( Base Class ) لمجموعه من الفئات فانه باستطاعتك تمرير اي فئة من الفئات التي قامت بوراثة الفئة الام , !!

ولتطبيق ما سبق سوف نضيف فئة جديدة الى المشروع بحيث تكون هي الفئة الام لكل من الفئة TextFile Class و XmlFile Class حيث سوف يصبح شكل فئات المشروع كالتالي :

File Class
TextFile Class
XmlFile Class
Employee  Class

حيث تعتبر الفئة File Class هي الفئة الام التي سوف ترثها كلاً من TextFile Class و XmlFile Class وهي ايضاً الفئة التي سيتم تمريرها لل Methode المسماة AddNewEmployee حيث ان شكلها سيصبح كالتالي :

void AddNewEmployee(File* FileObj,char* FileName){
		FileObj->SaveFile(FileName);
	};

لاحظ اننا الان لسنا مضطرين الى الدخول الى ال Methode السابقة كلما ظهر نوع ملفات جديد حيث يكفي بناء فئة تمثل نوع ذلك الملف وجعله بكل بساطة يرث من الفئة File ومن ثم تمريره الى ال Methode المسماة AddNewEmployee ,,

وهذا هو الكود كاملا :

#include<iostream.h>
#include<stdio.h>


class File{

public :
	virtual void SaveFile(char* FileName)=0;

};


class TextFile : public File{

public :
	void SaveFile(char* FileName){
		cout<<"Text File has been saved in "<<FileName<<"		 \n";
	};
};

class XmlFile: public File{

	void SaveFile(char* FileName){
		cout<<"Text File has been saved in "<<FileName<<"		 \n";
	};

};

class Employee {

public:

	void AddNewEmployee(File* FileObj,char* FileName){
		FileObj->SaveFile(FileName);
	};
};

main(){

Employee x;

x.AddNewEmployee(new TextFile,"c:\\Dr.Pain.txt");
x.AddNewEmployee(new XmlFile,"c:\\Dr.Pain.xml");

// u can add more clases here 
//x.AddNewEmployee(new HtmlFile,"c:\\Dr.Pain.html");
//x.AddNewEmployee(new XHtmlFile,"c:\\Dr.Pain.xhtml");

};

مرة اخرى جزاك الله خيراً اخي time1 والف الف الف شكر لك يا غالي ولكل اعضاء منتدانا الغالي ,,

اخوكم Dr.Pain

polymorphism.rar

#6

اشكرك جزيل الشكر استاذي Dr.Pain الفاضل على مشاركتك , واشكرك ايضا على المثال الرائع .

ربما يعتبر استخدام الـ polymorphism شي تعقيدي لدى البعض ,, الا انه في حقيقة الأمر أمر اساسي في جميع الفئات العامة . وهو يزيد من بدأ "تعميم البرامج "

llback.jpg

اشهد ان لا إله إلا الله وان محمدا ً رسول الله

#7

بسم الله الرحمن الرحيم

بارك الله فيك يا اخي العزيز و جعله في ميزان حسناتك

شكراً على الدرس الجميل و الأسلوب الرائع

إلى الأمام

#8

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

اقتباس
اشكرك جزيل الشكر استاذي Dr.Pain الفاضل على مشاركتك

دا انت إيلي استاذ و أبو الاساتذه يا time1 :lol: :lol: :lol:

انا صراحة استفدت كثيراً من الدروس ااتي قمت بوضعها انت :lol: :lol:

الشكر لله يا سريع :lol:

اخوكم Dr.Pain

#9

الرد متأخر شوي

بس الله يعطيك ألف عافية.

أيوا هيك يا شباب ......خللو المنتدى يرجع لأيام شبابه....الكل بيوخذ....والكل بيعطي.

------------------------------------------

هذا الموضوع مغلق.

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