ماجددج

البرمجة غرضية التوجة Oop [دورة مفصلة]

26 ردود في هذا الموضوع

bsm.gif

salam.gif

يسرني أن أقدم لكم أخواني الكرام هذه الدورة الطويلة بعض الشيء ، سيتم فيها بإذن الله شرح لما هي البرمجة غرضية التوجه أو ما يعرف بـ OOP ، وسيتم بإذن الله تعالى شرح لمواضيع عديدة ومتفرقة في هذا المجال ، من تلك الدروس التي سندرسها :

fa9l.gif

** مقدمة عامة تشمل المفاهيم الأساسية ومزايا البرمجة الشيئية .

** مستويات الحماية وإنشاء الأصناف واستدعاء الأعضاء ( البيانات والدوال ).

** مؤثر دقة الوصول ( :: ) Scope Resolution Operator .

** دوال البناء والهدم .( 1 و 2)

** المؤشر الحسابي & الحجز الديناميكي للذاكرة باستخدام new & delete .

** الكائنات والدوال الثابتة constant objects & constant Functions .

** المؤشر This .

** الأعضاء الساكنة static datda member.

** الدوال الصديقة friend functions .

** الأصناف الصديقة Friend Classes .

** الدوال الخطية Inline Functions.

** التحميل الزائد للدوال Function Overloading .

** التحميل الزائد للمؤثرات Operator Overloading .

** التحويل بين الأنواع Converting between types .

** الوراثة : أ: الوراثة الأحادية . ب: الوراثة المتعددة.

ملاحظة مهمة : الرجاء قراءة صفحات الموضوع كاملاً لان هناك العديد من الدروس الفرعية لم توضع لها وصلات هنا ، وأيضاً وجود بعض المشاركات والتوضيحات من الأخوان وفقهم الله أجمعين ..

fa9l.gif

وكل أملي بإذن الله أن أكون قد اخترت ما يناسبكم وأن تنال هذه المواضيع على استحسانكم ورضاكم ..

end.gif

fa9l.gif

البرنامج أو المترجم الذي سنعمل عليه هو Dev - c++ أنقر هنا لزيارة الصفحة الرئيسية للمترجم .

ولتحميل البرنامج مباشرة .::

Download.gif

fa9l.gif

تم تعديل بواسطه time1
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

** معنى البرمجة الشيئية :: oop

هي عبارة عن أسلوب جديد من أساليب البرمجة حيث أصبحت وحدة بناء البرنامج هي الصنف class والذي يحوي على البيانات data والعمليات ( الدوال ) functions .

ولها عدة مسميات منها ..::

1- البرمجة غرضية التوجة .

2- البرمجة الكائنية الموجهة .

fa9l.gif

* أسلوب البرمجة الشيئية :.

عادة ما تكون البرامج من هذا الأسلوب معقدة بشكل كبير حيث تقسيم البرنامج إلى مجموعة من المهام الرئيسية ومن ثم تقسم إلى مهام فرعية على حسب درجة التعقيد للمهام الرئيسية لذلك فان البرمجة الهيكلية تنتهج النهج ( من الأعلى إلى الأسفل ) Top Down .

fa9l.gif

* عيوب هذا الأسلوب : البرمجة الهيكلية .::

1- صعوبة فصل البيانات على العمليات .

2- إعادة إنشاء الحلول وعدة إعادة استخدامها .

fa9l.gif

* المفاهيم الأساسية للبرمجة الشيئية :.

1- الكائن Object :

عبارة عن وحدة تحوي مجموعة من البيانات تسمي ( خصائص ) properties أو صفات ومعرفة عليها مجموعة من العمليات .

مثال .:: كائن السيارة .:

الخصائص :

Model :Ferrari

Color : Blue

Year : 2005

العمليات ::.

Start ' الانطلاق '

Stop ' التوقف '

Accelerate 'التسارع'

fa9l.gif

2- الصنف Class : الكائنات ذات الخصائص والأفعال المشتركة بحاجة لآن تجمع مع بعضها البعض حتى يمكن استخدامها في برنامج ما.

وبالتالي فإن الصنف : عبارة عن مجموعة من الكائنات التي تشترك في الخصائص والعمليات ..

مثلاً ..::

الطالب كائن >> الطلاب صنف .

الموظف كائن >> الموظفين صنف .

fa9l.gif

* مزايا البرمجة الشيئية :. Features of (opp)

1- التجريدabstraction : وهو عملية تحديد الخصائص والعمليات التي تنتمي لصنف معين وهي نوعان .::

أ- تجريد البيانات Data abstraction : وهي عملية التعرف على الخصائص المرتبطة بكائن معين .

ب- تجريد العمليات Methods abstraction: وهو عملية تحديد العمليات والإجراءات دون ذكر شيء عن كيفية أدائها .

2- التغليف ( الكبسلة )Encapsulation : هي عملية تجميع كل الخصائص properties والطرق ( العمليات ) Methods في وحدة واحدة ( داخل غلاف واحد ) حيث لا يمكن الوصول إليها ( أي الخصائص والطرق ) إلا عن طريق الكائن .

3- إخفاء البيانات Data Hiding:. وهي ميزة ناتجة عن كبسلة البيانات وتعني إضافة مستوى حماية معين على البيانات حتى نمنع وصول الخطأ إليها .

4- الوراثة Inhertance:. وهي أن يرث صنف ما الخصائص والعمليات الموجودة في الصنف الآخر مما يساعد على إعادة الاستخدام للأصناف التي تم إنشاؤها من قبل المستخدم . .

fa9l.gif

** أمثلة لبعض الأصناف المشتقة والأساسية في الوراثة :..

1.gif

5- تعدد الأشكال ( الأوجه ) polymorfisme: تسمح ميزة تعدد الأشكال لنفس الدالة أن تتعرف بصورة مختلفة في أصناف مختلفة .

ويمكن عمل ذلك بـ الوراثة مع تعدد الأشكال .

واللغات التي تدعم أسلوب البرمجة الشيئية كثيرة نذكر منها ..

C++ و java و C# و vb.net

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

الدرس الثاني :..

fa9l.gif

** مستويات الحماية ( محددات الوصول للعضو ) .:

هي عملية تحديد مدى التعامل مع الأعضاء ( البيانات والعمليات ) . هل هذه الأعضاء خاصة بالصنف المعرفة فيه ، أم يمكن استخدام نطاق الصنف وهي ثلاث مستويات .::

1- مستوى الحماية الخاص private :

وفيه يتم تعريف الأعضاء التي يتم استخدامها في الصنف ، ولا يمكن الوصول إليها من خارج الصنف .

2- مستوى الحماية المحمي protected :

الأعضاء المعرفة في هذا المستوى تشبه الأعضاء الخاصة غير أنه يمكن توريثها إلى أي صنف آخر .

3- مستوى الحماية العام Public :

وفيه يتم تعريف الأعضاء العامة التي يمكن الوصول إليها من خارج الصنف .

fa9l.gif

* ملاحظات :.

1- دائماً تتبع محددات الوصول للعضو بنقطتين ( : ) مثلاً

Private:

2- يمكن أن تظهر عدة مرات وبأي ترتيب في تعريف الصنف .

3- يتم إعادة تعريف البيانات الأعضاء في مستوى الحماية الخاص Private لأن من مبادئ البرمجة الشيئية " إخفاء البيانات " .

4- يتم إعادة تعريف الدوال الأعضاء في مستوى الحماية العام لآن هذه الدوال يتم استدعاؤها من خلال البرنامج الرئيسي .

5- من الممكن أن يكون لدينا بيانات عامة وعمليات خاصة غير أن هذا الاستخدام غير شائع .

fa9l.gif

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

** الأصناف Classes :

fa9l.gif

تعريف الصنف : هو عبارة عن وحدة تحوي مجموعة من البيانات ( الخاصة والعامة )بالإضافة إلى تعريف الدوال ( العمليات ) حيث يطلق على الدوال المعرفة داخل الصنف بـ " أعضاء دالية " member Function .

fa9l.gif

* الإعلان عن الصنف :

2.gif

أمثلة :.

مثال 1: مثال على صنف الوقت .::

class Time
{
private:
int hor ,minute ,second;
public:
void settime(int,int,int);
void printstandard ();
void printmilitary();
};

fa9l.gif

مثال 2 : مثال على صنف المستطيل :.

class rectangle
{
int x,y;
public:
void set_value(int,int);
int area();
};

بمجرد تعريف الصنف يمكن استخدامه كنوع جديد حيث يطلق عليه ( نوع معرّف من قبل المستخدم).

fa9l.gif

** تعريف الكائنات .::

يتم تعريف الكائنات في البرنامج الرئيسي وفقاً للصيغة التالية :

class_name object_name

حيث :

class_name : اسم الصنف ( نفس اسم الصنف الذي كتبناه في بداية البرنامج )

object_name : اسم الكائن ، وهو اختياري ، يستخدم للوصول لعناصر الصنف .

fa9l.gif

مثال.::

rectangle rect;

حيث rectangle اسم الصنف ، و rect اسم الكائن .

وإذا أردنا أن نعرف أكثر من كائن بنفس الوقت ، نفس العملية السابقة ، فقط نفصل بين كل كائن والآخر باشارة الفاصلة ( , ) . والمثال التالي يوضح ما سبق .::

rectangle rect1,rect2,rect3;

fa9l.gif

** استدعاء الأعضاء :.

أعضاء الصنف لا يمكن أن نصل إليها من خارج الصنف إلا عن طريق الكائنات ويتم ذلك بالصيغة التالية :

Object_name.member

حيث .::

Object_name : اسم الكائن .

member : اسم العضو الذي نريد الوصول إليه .

مثال : إذا أردنا الوصول للدالة area() باستخدام الكائن rect نكتب الآتي :

rect1.area()

fa9l.gif

البرنامج الأول : نقوم بكتابة برنامج يقوم بحساب مساحة المستطيل ( باستخدام الأصناف ) ..

#include <iostream.h>
#include <cstdlib>
using namespace std;
class rectangle
{
int x ,y;
public :
void set_value(int a,int b)
{
x=a;
y=b;
}

int area()
{
return x*y;
}
};
main()
{
rectangle rect1,rect2;
rect1.set_value(3,4);
rect2.set_value(5,6);
cout<<"Rect1 Area = "<<rect1.area()<<endl;
cout<<"Rect2 Area = "<<rect2.area()<<endl;
system("PAUSE");

}

شرح للبرنامج :.

في البداية عرفنا متغيرات خاصة Private وهما x ,y وهنا ملاحظة وهي طالما أننا عرفنا ذلك في بداية الصنف ولم نحدد مستوى الحماية فإن مستوى الحماية الإفتراضي هو Private .

بعد ذلك أنشأنا دالة باسم set_value بوسيطين في مستوى الحماية العام Public وظيفة هذه الدالة هي مساواة القيم التي يحددها المستخدم بالمتغيرات الخاصة ، أو بمعنى أخر وظيفتها الوصول للمتغيرات الخاصة x,y .

بعد ذلك أنشأنا دالة area() وظيفتها إرجاع مساحة المستطيل وهي عملية حسابية

الطول × العرض .

ثم في الدالة الرئيسية main() قمنا في البداية في باشتقاق كائنين rect1 و rect2 بعد ذلك قمنا باستدعاء دالة set_value وحددنا قيم الوسائط ..

ثم بعد ذلك استدعينا دالة حساب المساحة area() لكل من الكائنين rect1 ,rect2 .

fa9l.gif

** البرنامج الثاني : برنامج يقوم بحساب مساحة ومحيط الدائرة ( مستخدماً الأصناف ) .::

#include <iostream.h>
#include <cstdlib>
using namespace std;
class circle
{
private :
int r;
float area1,c;
public :
void get_r()
{
cout<<"Enter radius \n";
cin>>r;
}
void area()
{
area1=r*r*3.14;
}
void cir()
{
c=2*r*3.14;
}
void display ()
{
cout<<area1<<endl;
cout<<c<<endl;
}
};
main()
{
circle c;
c.get_r();
c.area();
c.cir();
c.display();
system("PAUSE");

}

نفس المثال السابق تقريباً من حيث الفكرة حيث :..

r = نصف القطر . area1=المساحة. c = المحيط .

cir = دالة ايجاد المحيط . display= طباعة المساحة والمحيط . area= المساحة .

fa9l.gif

تمرين ..:: أكتب برنامج يقوم بايجاد مضروب عدد مدخل من قبل المستخدم ( مستخدماً الأصناف ) ..

fa9l.gif

أي سؤال أو أستفسار على ما مضى أنا في الخدمة .

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

مؤثر دقة الوصول Scope Resolution Operator

عبارة عن مؤثر يستخدم عندما تكتب تفاصيل الدالة العضو خارج الصنف .

** الصيغة العامة للدالة التي تكتب خارج الصنف هي :

DataType ClassName::FunctionName (Function Arguments )

fa9l.gif

** دوال البناء والهدم ::

أولا: دوال البناء Constructor Function .:::

هي عبارة عن دالة تحمل نفس اسم الصنف ويتم استدعاؤها مباشرة عند اشتقاق كائن من الصنف وتستخدم غالباً لإعطاء خصائص ( متغيرات ) الصنف قيم ابتدائية .

fa9l.gif

- ملاحظات :

1- لا يمكن تهيئة البيانات العضو أثناء التعريف .

2- لا يوجد مردود ( return ) لدوال البناء .

3- يمكن أن يحوي الصنف أكثر من دالة بناء ( التحميل الزائد للدوال ).

fa9l.gif

** مثال توضيحي لمؤثر دقة الوصول ودوال البناء .:

#include <iostream.h>
#include <cstdlib>
using namespace std;
//انشاء صنف باسم MYCLASS
class myclass
{
int a;
public:
myclass();
void show();
};
myclass::myclass()
{
cout<<"Constructor Function \n";
a=10;
}
void myclass::show()
{
cout<<"a="<<a<<"\n";
}
int main()
{
myclass ob;
ob.show();

system("PAUSE");
return 0;
}

والان شرح بسيط لاهم ما ورد في الكودالسابق :

myclass();

الاعلان عن دالة بناء ( لان اسمها من اسم الصنف ) ولاحظ اننا وضعنا في نهاية تعريف الدالة فاصلة منقوطة ( ; ) وهذه نضعها في حال لم نريد كتابة تفاصيل الدالة داخل الصنف .

myclass::myclass()

لاحظ اننا كتبنا هذا الكود بعد اقفال الكلاس .

لكتابة تفاصيل الدالة خارج الصنف نستخدم هذه الطريقة بحيث في البداية كتبنا اسم الصنف myclass ومن ثم مؤثر دقة الوصول وهو ( :: ) ومن ثم اسم الدالة myclass().(لاحظ هنا اننا نتحدث عن دالة البناء ، ودالة البناء ليس لها DataType عكس دالة show التي سترد الان ) .

void myclass::show()

لاحظ هنا في البداية نكتب نوع الدالة DataType وهو Void الموجود في دالة show ، ومن ثم اسم الصنف ومؤثر دقة الوصول واسم الدالة ( كما في الدالة السابقة)

fa9l.gif

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

** دالة الهدمDestructor Function :

هي عبارة عن دالة عضو في الصنف ، ويتشكل اسمها من المحرف ( ~ ) مضافاً إليه اسم الصنف . وتستخدم لإنهاء الأعمال الداخلية للكائنات حتى يستطيع النظام استعادة الذاكرة لحفظ كائنات جديدة .

ملاحظات على دالة الهدم :

1- ليس لها وسائط ، ولا ترجع فيمة .

2- يمكن للصنف أن يحتوي على دالة هدم واحدة فقط .

3- لا يمكن تحميل دالة الهدم بشكل زائد.

fa9l.gif

** استخدام الوساط ( التلقائية ) الإفتراضية مع دالة :

يمكن أن يستخدم أي نوع أو أي عدد من المعاملات ( الوسائط) داخل دالة البناء ، في هذه الحالة يتم استدعاء دالة البناء للكائنات ذات المعاملات التي تتناسب مع عدد المعاملات الموجودة داخل دالة البناء .

مثال .:

#include <iostream.h>
#include <cstdlib>
using namespace std;
class myclass
{
private:
int x,y;
public:
myclass()
{
x=y=1;
}
myclass(int a ,int b)
{
x=a;
y=b;
}
void display()
{
cout<<"x="<<x<<endl;
cout<<"y="<<y<<endl;
}
};

int main()
{
int n,m;
cin>>n>>m;
myclass ob1;
ob1.display();
myclass ob2(n,m);
ob2.display();
system("PAUSE");
return 0;
}

توضيح بسيط لأهم ما ورد في هذا الكود :

في البداية يطلب البرنامج من المستخدم ادخال عددين ليسجلهما في المتغيرين m,n ..

و عند اشتقاق الكائن الأول وهو ob1 كما يظهر هنا ::..

 myclass ob1;

فإنه يتم مباشرة استدعاء التعليمات المكتوبة داخل دالة البناء myclass وهي ::.

 myclass()
{
x=y=1;
}

أي يجعل قيمة x و y تساوي العدد ( 1 ) .

ومن ثم استدعاء دالة الطباعة للكائن ob1 كما في هذا الشكل :.

 ob1.display();

بعد ذلك تم اشتقاق كائن اخر من الصنف myclass باسم ob2 وله وسيطتين وهما العددين الذين ادخلهما المستخدم في بداية البرنامج .::

 myclass ob2(n,m);
ob2.display();

ليتم بعدها طباعة العددين m,n من خلال دالة الطباعة display()

fa9l.gif

** متى تستدعى دوال البناء والهدم ؟!

1- يعتمد الترتيب الذي يستدعى به هذه الدوال على ترتيب الذي يدخل فيه التنفيذ أو يخرج من المجال الذي عرفت فيه الكائنات .

2- بشكل عام . يتم استدعاء دوال الهدم بترتيب معاكس لدوال البناء غير أنه يمكن أن يتغير هذا الترتيب في بعض الحالات ( ستذكر في السياق |38|)

3- تستدعى دوال البناء للكائنات المعرفة في المجال العام وقبل تنفيذ أي دالة بما فيها الدالة Main() .

4- تستدعى دوال الهدم المقابلة عندما تنتهي الدالة main().

5- تستدعى دوال البناء للكائنات المحلية التلقائية عندما يصل التنفيذ إلى النقطه التي عرفت فيها الكائنات .

6- تستدعى دوال الهدم المقابلة عندما تغادر الكائنات المجال الذي عرفت فيه .

7- تستدعى دوال البناء للكائنات المحلية الساكنة عندما يصل التنفيذ إلى النقطة التي عرّفت فيها الكائنات وتستدعى دوال الهدم المقابلة عند انتهاء الدالة Main() .

fa9l.gif

** برنامج يوضح لك النقاط السابقة حتى تتضح الرؤية حول كيفية الاستدعاء |40|

#include <iostream.h>
#include <cstdlib>
using namespace std;
class createAndDestroy
{
private:
int data;
public:
createAndDestroy (int);
~createAndDestroy();
};
createAndDestroy::createAndDestroy(int value)
{
data=value;
cout<<"object "<<data<<" Constructor \t";
}
createAndDestroy::~createAndDestroy()
{
cout<<"object"<<data<<"destructor"<<endl;
system("PAUSE");
}
void create();
createAndDestroy first(1);


int main()
{
cout<<"global object before main"<<endl;
createAndDestroy second(2);
cout<<"Local Automatic in main"<<endl;
static createAndDestroy third(3);
cout<<"Local Static in main"<<endl;
create();
createAndDestroy fourth(4);
cout<<"Local Aotumatic in main"<<endl;

system("PAUSE");
return 0;
}


void create()
{
createAndDestroy fifth(5);
cout<<"Local Aotumatic in Create \n";
static createAndDestroy sixth(6);
cout<<"Local Static in create \n";
createAndDestroy seventh(7);
cout<<"Local Automatic in Create \n";
system ("PAUSE");
}

وهذا هو شكل المخرجات :

post-58588-1202936059_thumb.jpg

توضيح بسيط للبرنامج :.

في البداية يقوم بتنفيد دوال البناء لكل من ( 1 ، 2 ، 3 ) بعدها يقفز للأسفل لقراءة تفاصيل الدالة Create();فيقرأ كل من ( 5 ، 6 ، 7 )

وبعدها بعملية عكسية يتم الهدم "مثل ما ذكر سابقاً" فيتم الهدم لكل من ( 7 )

وبعدها لا يحدف (6) لانه ساكن Static فينتقل للتي بعدها وهي ( 5) فيتم هدمها وبعد ذلك يعود للبرنامج الرئيسي فيقوم بتنفيذ ( 4 ) ومن بعدها تنتهي الدالة Main() فيقوم البرنامج بالهدم بعملية عكسية أيضاً فيهدم ( 4 ) ومن ثم ( 2) " 3 لا يهدم لانه ساكن حاله حال 6 " ومن بعدها يهدم الدالة 2 ..

الان يهدم وبعد الانتهاء من هدم الدوال العامة يعود لهدم الدوال الساكنة فيهدم ( 6 ) ومن بعدها يهدم الدالة رقم ( 3 ) .. وفي الأخير يتم هدم الدوال العامة ولا يوجد لدينا الا دالة واحده وهي ( 1 ) .

fa9l.gif

لنا عودة قريباً ان شاء الله لمتابعة الدروس باذن الله ..

وفقني الله وإياكم لكل خير ...

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

** المؤشر الحسابي :

عند الحديث عن مؤشر الكائن يظهر مفهوم جديد وهو المؤشر الحسابي ونقصد به : أن مؤشر الكائن ربّما يخضع لبعض العمليات مثل :

1- ( ++ ) وتعني زيادة قيمة المؤشر Increment وتستخدم لجعل المؤشر يشير إلى الموقع التالي..

2- ( -- ) وتعني إنقاص المؤشر Decrement وتستخدم لجعل المؤشر يشير إلى الموقع السابق .

مثال :

#include <iostream> 
#include <cstdlib>
using namespace std;
class samp
{
int a, b;
public:
samp(int m,int n)
{
a=n;
b=m;
}
int get_a()
{
return a;
}
int get_b()
{
return b;
}
};
int main()
{
samp ob[4]={samp(1,2),samp(3,4),samp(5,6),samp(7,8)};
samp *x;
x=&ob[0];
for (int i=0;i<4;i++)
{
cout<<x -> get_a()<<"\t"<<x -> get_b()<<"\n";
x++;
}
system("PAUSE");
return 0;
}

في هذا المثال لدينا مصفوفة من الكائنات كما يظهر في الكود :

samp ob[4]={samp(1,2),samp(3,4),samp(5,6),samp(7,8)};

ولدينا المؤشر للعنصر الأول :

samp *x; 
x=&ob[0];

اذا فنحن نستطيع التنقل الى الكائنات الأخرى من خلال Pointer Arithmatic وهو في حالتنا هذه x++ أي أذهب الى الكائن الأخر في المصفوفه وهكذا إلى ان يصل للكائن الأخير وستكون المخرجات بالشكل التالي :..

1 2

3 4

5 6

7 8

( المثال من تعديل وتوضيح استاذنا الفاضل romansy )

fa9l.gif

الحجز الديناميكي للذاكرة باستخدام new & delete :

في لغة c++ نستخدم المؤشر new لحجز الذاكرة الديناميكية و delete لإلغائها .

- الصيغة العامة لحجز ذاكرة وإلغائها لكائن واحد هي :.

p-var=new type;
delete p-var;

أما في حالة عدة مواقع فإننا نستخدم الصيغة التالية :.

p-var = new type[size];
delete[] p-var;

حيث Type تحدد النوع ( اسم الصنف ) ، وP-Var مؤشر النوع .

fa9l.gif

مثال على حجز موقع واحد وإلغائه .:::( لابد أن تكون مطلع على موضوع المؤشرات والمراجع )

#include <iostream.h>
#include <cstdlib>
using namespace std;
class samp
{
int i ,j;
public:
void set_ij(int a , int b)
{
i=a;
j=b;
}
int get_product()
{
return i*j;
}
};
int main()
{
samp *p;
p= new samp;
p -> set_ij(4,5);
cout<<p -> get_product()<<"\n";
delete p;

system("PAUSE");
return 0;
}

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

#include <iostream.h>
#include <stdlib.h>
class samp
{
int i ,j;
public:
void set_ij(int a , int b)
{
i=a;
j=b;
}
int get_product()
{
return i*j;
}
};
int main()
{
samp *p;
int n;
cin>>n;
p=new samp[n];
for ( int i=0;i<n;i++)
{
p -> set_ij(i,i);
cout<<p -> get_product()<<"\n";
}
delete []p;

system("PAUSE");
return 0;
}

وهذاالمثال كما ذكرت نفس المثال السابق ولكن لعدة مواقع بحيث في البداية يتم ادخال رقم ( مثلاُ 7 ) ومن يقوم بطباعة حاصل ضرب الأعداد في نفسها من 1 إلى 6 ( 1*1 ، 2*2 ، ... ، 6*6) وتظهر المخرجات كما في الشكل التالي:

6.jpg

fa9l.gif

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

مساواة الكائنات :

يمكن مساواة كائن بكائن أخر مثلاً إذا كان لدينا كائنين A و B إذا جعلنا ( A=B ) فهذه العملية تعني نسخ محتويات الكائن B بالكائن A .

ملاحظات :

1- يجب أن تكون الكائنات من نفس النوع وإلا أدى ذلك إلى خطأ .

2- يمكن إرسال الكائن كوسيطة للدالة ، كما يمكن إرجاعه من الدالة .

fa9l.gif

مثال :

#include <iostream.h>
#include <cstdlib>
using namespace std;
class date
{
int day,mounth,year;
public:
date(int=1,int=1,int=1990);
void print();
};
date:: date(int m,int d,int y)
{
mounth=m;
day=d;
year=y;
}
void date::print()
{
cout<<mounth<<"_"<<day<<"_"<<year;
}
int main()
{
date date1(7,4,1993),date2;
cout<<" date1= ";
date1.print();
cout<<"\n date2= ";
date2.print();
date2=date1;
cout<<"\n date2= ";
date2.print();
cout<<"\n";
system("PAUSE");
return 0;
}

كما هو ظاهر في هذا المثال وهو خاص بطباعة التاريخ ، قمنا في البداية بتعريف دالة بناء افتراضية ذات ثلاثة معاملات وهي اليوم والشهر والسنة ، ومن ثم قمنا بتعريف دالة للطباعة .

قمنا بعدها باشتقاق كائنين الأول date1 قمنا من خلاله بإرسال المعاملات أو الوسائط وهي اليوم والشهر والسنة(7,4,1993) ، والكائن الثاني date بدون وسائط ( بحيث ينفذ الوسائط التلقائية الموجودة في دالة البناء وهي 1-1-1990) .

بعدها قمنا بطباعة محتويات الكائن الأول وهي 7-4-1993ومن ثم طباعة محتويات الكائن الثاني وهي 1-1-1990

بعد ذلك قمنا بنسخ محتويات الكائن date1 بالكائن date2 كما يظهر في هذا الكود

date2=date1;

بعد ذلك قمنا بطباعة محتويات الكائن الثاني لتظهر لنا 7-4-1993 .

fa9l.gif

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

** إرسال الكائن إلى دالة :

fa9l.gif

تسمح لغة C++ بإرسال الكائنات إلى الدوال كما يتم إرسال المعاملات البسيطة ، ويمكن توضيح ذلك في المثال التالي:

#include <iostream.h>

#include <cstdlib>

using namespace std;

class sample

{

int i;

public:

sample (int n)

{

i=n;

}

int get_i()

{

return i;

}};



int sqr_i(sample ob)

{

return ob.get_i()*ob.get_i();

}

int main()

{

sample s1(2),s2(10);

cout<<sqr_i(s1)<<endl;

cout<<sqr_i(s2)<<endl;



system("PAUSE");

return 0;

}

توضيح مبسط لأهم ما ورد في الكود السابق :

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

ظهر في هذا المثال الدالة التالية :

int sqr_i(sample ob)

الدالة sqr_i له وسيطة واحدة وهي الكائن ob المشتق من الصنف sample ،حيث يتم من خلال هذا الكائن الوصول للدوال الموجودة داخل الصنف sample فكما ظهر قمنابالوصول للدالة get_i() والتي وظيفتها الوصول للمتغيرات الموجودة في مستوى الحماية الخاص Private .

بعد ذلك قمنا باشتقاق كائنين s1 الذي يرسل القيمة ( 2 ) لدالة البناء sample بعد ذلك يتم طباعة حاصل العدد (2) في نفسه من خلال الدالة sqr_i التي تستقبل وسيطة واحدة وهي الكائن s1 .

وكذا الحال مع الكائن الاخر s2 .

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

** الكائنات الثابتة والدوال الثابتة :

fa9l.gif

على حسب حاجة البرنامج قد تكون لدينا كائنات غير قابلة للتعديل والبعض الآخر قابل للتعديل ، لجعل الكائن غير قابل للتعديل نستخدم الكلمة المفتاحية Const مثلاً

Const time t(12,00);

ملاحظات :

1- لا تسمح مترجمات لغة C++ لأي دالة عضو باستدعاء كائنات ثابتة مالم يصرح عن الدوال العضو نفسها كدوال ثابتة.

2- دوال العضو المصرح عنها كدوال ثابتة لا يمكن أن نعدل على الكائن حيث لا يسمح المترجم بذلك .

3- يتم الإعلان عن الدالة الثابتة باستخدام الكلمة المفتاحية const في تعريفها وعند كتابة التفاصيل مثلاً :

int get_hour()const;

OR

Int get_hour()const
{
----
--
}

4- استدعاء دالة عضو غير ثابتة non const على كائن ثابت تعتبر خطأ قواعدياً .

مثال :

#include <iostream.h>
#include <cstdlib>
using namespace std;
class increment
{
int count;
const int incre;

public:
increment (int c=0, int i=1);
void addincement()
{
count+=incre;
}
void print()const;
};
increment::increment(int c,int i):incre(i)
{
count=c;
}
void increment::print()const
{
cout<<"Count= "<<count<<" , incre = " <<incre<<endl;
}
int main()
{
increment value(10,5);
cout<<"Before Increment :";
value.print();
for(int j=0;j<3;j++)
{
value.addincement();
cout<<"After Inrement :"<<j+1<<":";
value.print();
}

system("PAUSE");
return 0;
}

مثال بسيط جداً بحيث جعلنا المتغير incre متغير ثابت const بحيث تكون قيمته ثابتة ، ومتغير اخر باسم count ومن قم في كل مرة يضيف قيمة المتغير incre إلى المتغير count ويطبع قيمة المتغيرين ، وستظهر المخرجات بهذا الشكل ::

7.jpg

نقطه هامة جداً بخصوص الدالة increment .

لاحظ اننا كتبناها بهذه الصيغة ( لاحظ المتغير incre )

increment::increment(int c,int i):incre(i)
{
count=c;
}

في الأصل المفروض كما ورد في امثلة سابقة ان تكون بهذه الصيغة

increment::increment(int c,int i)
{
count=c;
incre=i;
}

لكن في المتغيرات الثابتة const فاننا لا نعرفها بهذا الشكل ...

تم تعديل بواسطه ماجددج
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

** الدوال الصديقة والأصناف الصديقة Friend Classes & Friend Functions

fa9l.gif

تعريف الدالة الصديقة : هي عبارة عن دالة تفاصيلها خارج الـ Class مع امتيازها بحق الوصول لجميع أعضاء الـ Class .

- للتصريح عن الدالة الصديقة نستخدم الكلمة المفتاحية friend كما يلي :

Friend DataType FunctionName (Parameters)

OR

DataType friend  FunctionName (Parameters)

ملاحظات :

1- مع أن تعريف الدالة الصديقة يتم داخل الصنف ، إلا أنها لا تعتبر دالة عضو من أعضاء الصنف ، لذلك من الخطأ استدعاؤها باستخدام اسم الكائن مع أداة الوصول ( . ) .

2- لا تؤثر مستويات الحماية على التصريح عن الدالة الصديقة لذلك يمكن التصريح عن الدالة الصديقة في أي موضع داخل الصنف .

3- الدالة الصديقة لها امتيازات الدالة العضو في الصنف ، أي أنها لها المقدرة على الوصول إلى جميع خصائص الصنف .

4- يتم استدعاء الدالة الصديقة عن طريق اسمها مع الوسائط .

fa9l.gif

* مثال : برنامج يتم فيه التصريح عن الدالة الصديقة setx والتي تستخدم في الوصول إلى عضو البيانات الخاص x .

#include <iostream.h>
#include <cstdlib>
using namespace std;
class count
{
friend void setx (count&,int); //تعريف لمرجع كائن
private:
int x;
public:
count(){x=0;}
void print()const
{
cout<<x<<endl;
}};
void setx (count &c,int val)
{
c.x=val;
}
int main()
{
count counter;
counter.print();
setx(counter,8);
counter.print();

system("PAUSE");
return 0;
}

هذا المثال بسيط جداً يوضح آلية التعامل مع الدوال الصديقة بحيث يتم في البداية تعريف الدالة في أي موقع داخل الـ Class كما في الشكل التالي :

friend void setx (count&,int);

كما يظهر الدالة تحتوي على وسيطة Parameter مرجع لكائن والأخرى متغير ، وطريقة كتابة التفاصيل خارج الـ Class كما ظهر في هذا الشكل :

void setx (count &c,int val)
{
c.x=val;
}

كما ظهر فانه تم الوصول للمتغير x الموجود في مستوى الحماية private مباشرة ومن ثم تخزين القيمة الموجودة في المتغير val في المتغير x ..

بعد ذلك :

count counter;
counter.print();
setx(counter,8);
counter.print();

كما ظهر في البداية يستدعي دالة البناء count والتي تجعل قيمة المتغير x تساوي القيمة 0 ومن ثم طباعة هذه القيمة .

بعد ذلك يتم التعامل مع الدالة setx بحيث نغير قيمة المتغير x بجعلها تساوي الرقم 8 ومن ثم طباعتها ...

هذا باختصار فكرة عمل هذا البرنامج ..

fa9l.gif

مثال2 : برنامج يستخدم دالة صديقة تقارن بين نصفي قطري دائرتين ( إيجاد المساحة والمحيط لكل دائرة ) :

#include <iostream.h>
#include <stdlib.h>
class circle
{
int r;
float ar,c;
public:

circle (int r1){r=r1;}
void area ()
{
ar=3.14*r*r;
}
void cir()
{
c=2*3.14*r;
}
void display()
{
cout<<"area = "<<ar<<endl;
cout<<"cir = "<<c<<endl;
}
friend bool compare (circle,circle);
};

bool compare (circle c1,circle c2)
{
return c1.r>c2.r;
/*
أو بالامكان كتابة الشرط كاملاً كما في هذا الشكل
if (c1.r>c2.r)
cout<<"r1 is greator";
else
cout<<"r2 is gretaor"

*/

}
int main()
{
int r1,r2;
cout<<"Enter radios r1"<<"\n";
cin>>r1;
cout<<"Enter radios r2"<<"\n";
cin>>r2;
circle cc1(r1),cc2(r2);
cc1.area();
cc1.cir();
cc1.display();
cc2.area();
cc2.cir();
cc2.display();
if (compare (cc1,cc2))
/*
وهنا يكفي السطر الأول فقط في حال طبقنا الكود المكتوب
في الملاحظة السابقة
if (compare (cc1,cc2))
*/
cout<<"r1 is greator";
else
cout<<"r2 is greator";

system("PAUSE");
return 0;
}

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

** الأصناف الصديقة Friend Classes :

fa9l.gif

تعريف : هو عبارة عن صنف تستطيع كل دواله الأعضاء أن تستخدم خصائص الصنف الآخر .

- وللتصريح عن الصنف الصديق : نستخدم الكلمة المفتاحية friend مثلاً لجعل الصنف tow صديق للصنف one نكتب العبارة التالية :

Friend class tow

داخل الصنف one .

ملاحظات :

1- يمكن التصريح عن الصنف الصديق بأي موضع داخل الآخر .

2- علاقة الصداقة ليست تناظرية ، بمعنى إذا كان الصنف A صديق للصنف B فهذا لا يعني أن الصنف B صديق للصنف A .

3- علاقة الصداقة ليست متعدية ، بمعنى إذا كان الصنف A صديق للصنف B والصنف B صديق للصنف C فهذا لا يعني أن الصنف A صديق للصنف C .

fa9l.gif

مثال توضيحي :

//تعريف للصنف فقط دون كتابة اي تفاصيل له
class a;
class b
{
/*
كافة التفاصيل الخاصة بالـ class b
*/
friend class a;
}
class a
{
/*
كافة التفاصيل الخاصة بالـ class a
*/

}

هذه الصيغة العامة للتعامل مع الأصناف الصديقة .

ملاحظة هامة جداً :الصنف الصديق لابد أن يعرف أولا ..

fa9l.gif

** مثال : برنامج يستخدم الأصناف الصديقة ، ويقوم بإيجاد الوسط الحسابي لـ N من الأعداد الحقيقية المدخلة من قبل المستخدم .بحيث

* الصنف الأول يستخدم لـ ( إدخال الأعداد ثم اثجاد مجموعها والذي نسميه بـ summation ).

* الصنف الثاني يستخدم المعلومات الموجودة في الصنف الأول summation ومن ثم إيجاد الوسط الحسابي والذي نسميه بـ mean ::..

#include <iostream.h>
#include <cstdlib>
using namespace std;
//تعريف الصنف الصديق أولاً
class mean;
class summation
{
//تم هنا تعريف الصنف الصديف داخل الصنف
friend class mean;
private:
//المتغير الذي يحدد عدد الاعداد المدخلة من قبل المستخدم
int n;
float x,sum;
public:
//داله بناء
summation()
{sum=0;

cout<<"Enter n :"<<endl;
cin>>n;
for(int i=1;i<=n;i++)
{
cout<<"Enter x ["<<i<<"] : \n";
cin>>x;
sum+=x;
}
cout<<"Summation="<<sum<<endl;
}};
class mean
{
private :
// متغير عدد حقيقي لتخزين المتوسط
float s;
public:
//لاحظ هنا الدالة لها وسيطة من نوع الكائن الصديق
//من خلالة يتم الوصول لكافة الأعضاء الموجودة بداخله مثل مجموع الاعداد
mean(summation ss)
{
s=ss.sum/ss.n;
cout<<"Mean = "<<s<<"\n";
}};
int main()
{
//يتم هنا استدعاء دالة البناء مباشرة
summation s;
//لاحظ هنا الوسيطة هي الكائن s
//لانه يحتفظ بكافة العمليات التي اجريناها
mean m(s);
system("PAUSE");
return 0;
}

fa9l.gif

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

** أعضاء الصنف الساكنة Static Class members :

fa9l.gif

البيانات الساكنة : هي عبارة عن خصائص ( متغيرات ) مشتركة بين كل كائنات الصنف ، أي أن كل الكائنات لها نفس النسخة من المتغيرات .

- وللتصريح عن البيانات الساكنة نستخدم المفتاحية static .

fa9l.gif

* ملاحظات :

1- لابد من تهيئة المتغيرات الساكنة لمرة واحدة فقط في البرنامج .

2-يمكن الوصول للمتغيرات الساكنة العامة باستخدام اسم الصنف مع مؤثر دقة الوصولScope Resolution Operator ( :: ) ، أو باستخدام اسم الكائنات .

مثلاً : ليكن لدينا الصنف Employee والذي يحمل المتغير الصحيح العام count لتهيئة هذا المتغير نكتب العبارة التالية :

int Employee :: count=0;

وللوصول لهذا المتغير في البرنامج الرئيسي نتبع أحد هاتين الطريقتين :

Employee::count

OR

 s.count

حيث s كائن تم اشتقاقه من الصنف Employee .

3- أي دالة تعامل مع بيانات ( متغيرات ) ساكنة لابد أن تكون ساكنة أيضاً . مثلاً

static void  display()
{
cout<<count;
}

حيث count هو متغير ساكن والذي سبق تعريفة في الملاحظة السابقة .

4- استدعاء الدالة الساكنة يتم باستخدام :

أ. مؤثر دقة الوصول Scope Resolution Operator .

ب. الكائنات .

fa9l.gif

مثال على البيانات الساكنة

#include <iostream.h>
#include <cstdlib>
using namespace std;
class staticproperty
{
public:
int static n;
staticproperty()
{
++n;
}
};
int staticproperty::n=3;
main()
{
staticproperty s1,s2,s3,s4;
cout<<s1.n<<endl;
cout<<staticproperty::n<<endl;
cout<<s4.n<<endl;
system("PAUSE");

}

كماهو ملاحظ لدنيا المتغير الساكن وهو n تم تعريفه في بداية الصنف :

int static n;

ومن ثم لدينا دالة البناء التي تزيد قيمة المتغير n بالعدد ( 1 ) من خلال مؤثر التزايد كما يظهر :.

staticproperty()
{
++n;
}

بعد ذلك تم تطبيق أمر مهم جداً (ملاحظة رقم 1) وهو تهئية قيمة المتغير وهنا في هذا المثال جعلنا n=3 وتم التعريف خارج الصنف باستخدام مؤثر دقة الوصول Scope Resolution Operator :

int staticproperty::n=3;

بعد ذلك تم اشتقاق أربعة كائنات من الصنف staticproperty :

staticproperty s1,s2,s3,s4;

لاحظ هنا دالة البناء تزيد قيمة المتغيرn بـ ( 1) وتم تهيئة قيمة المتغير بالعدد ( 3) فعند اشتقاق اي كائن تزيد قيمة n باضافة العدد 1 إلي القيمة السابقة .

فعند اشتقاق الكائن s1 أصبحت قيمة n تساوي العدد 4 .

وعند اشتقاق الكائن s2 أصبحت قيمةn تساوي العدد 5 .

وعند اشتقاق الكائن s6 أصبحت قيمةn تساوي العدد 6 .

وعند اشتقاق الكائن s7 أصبحت قيمةn تساوي العدد 7 .

وكما ذكرنا في التعريف الموجود في اول الرد

البيانات الساكنة : هي عبارة عن خصائص ( متغيرات ) مشتركة بين كل كائنات الصنف ، أي أن كل الكائنات لها نفس النسخة من المتغيرات .

أي ان :

s1 = s2 = s3 = s4

وجميع الكائنات تساوي اخر عملية تمت على اي كائن وهي اشتقاق الكائن s4 زادت قيمة المتغير n وأصبحت تساوي العدد 7 ..

أي عند طباعة أي كائن :.

staticproperty s1,s2,s3,s4;
cout<<s1.n<<endl;
cout<<staticproperty::n<<endl;
cout<<s4.n<<endl;

فستكون مخرجات هذا البرنامج هي ::

7

7

7

fa9l.gif

مثال (2) على الأعضاء ( الدوال ) الساكنة :

#include <iostream.h>
#include <cstdlib>
using namespace std;
class property
{
private:
int static n;
public:
property ()
{++n;}
static void display()
{
cout<<n<<endl;
}};
int property::n=2;
int main()
{
property s1,s2,s3;
property::display();

s1.display();
s3.display();
system("PAUSE");
return 0;
}

وهنا تم تعريف دالة display() على انها دالة ساكنة ::.

static void display()
{
cout<<n<<endl;
}

ومن ثم تم تهيئة قيمة المتغير n بالعدد ( 2 ) ::

int property::n=2;

بعدها تم اشتقاق الكائنات من الصنف property ::

property s1,s2,s3;

ونفس العملية في المثال الأول تتم هنا أيضاً .. حيث ان جميع الكائنات تحتوي على المتغير n الذي يساوي العدد ( 5 ) .

بعد ذلك تمت طباعة المخرجات بطرق مختلفة كما هو ظاهر ::.

property::display();

s1.display();
s3.display();

حيث في هذه الحالة تكون المخرجات بـ :

5

5

5

fa9l.gif

تمرين : وضح مخرجات هذا البرنامج ( دون استخدام اي مترجم )

#include <iostream.h>
#include <stdlib.h>
class sample
{
public:
int static n;
sample()
{
++n;
}
~sample()
{
--n;
}
};
int sample::n=5;
main()
{
sample a;
sample b[4];
sample *c=new sample[3];
cout<<c -> n<<"\n";
cout<<b[1].n<<"\n";
delete []c;
cout<<sample::n<<"\n";
cout<<a.n<<"\n";
system("PAUSE");
return 0;
}

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

** الدوال الخطية Inline Functions :

fa9l.gif

الدوال الخطية : عبارة عن دوال تقوم بتسريع تنفيذ البرنامج (لان كل موعد يتم فيه استدعاء الدالة الخطية يقوم المترجم بكتابة التفاصيل في موقع الاستدعاء)، ويمكن توضيح استخدام الدالة الخطية في لغة C++ كما في المثال التالي :.

#include <iostream.h>
#include <cstdlib>
using namespace std;
inline int cube (int a)
{
return a*a*a;
}
int main()
{
for (int i=0;i<10;i++)
{
cout<<cube(i)<<endl;
}
system("PAUSE");
return 0;
}

وبنفس هذا الأسلوب يمكن استخدام مفهوم الدوال الخطية مع الأصناف Classes حيث :

1- أي دالة تكتب تفاصيلها داخل الصنف يعتمد المترجم على أنها دالة خطية إلا إذا احتوت على حلقات تكرارية فيعتمد المترجم على أنها عادية .

2- يقوم المترجم بكتابة تفاصيل الدالة الخطية في كل موضع يظهر فيه استدعاء الدالة الخطية مما يقلل من وقت الذهاب والرجوع للدالة .

مثال :

class xy
{
private :
int g;
public:
void set (int x )
{
g=x;
}
};

لاحظ هنا أن الدالة set تعتبر دالة خطية لسببين :

1- تفاصيلها كتبت داخل الصنف .

2- لا تحتوي على حلقات تكرارية .

* إذا كتبت تفاصيل الدالة خارج الصنف لابد من إضافة inline إلى الدالة حتى تعتبر دالة خطية .

مثال :

#include <iostream.h>
#include <cstdlib>
using namespace std;
class sample
{
int i,j,k;
public:
sample (int a,int b)
{
i=a;
j=b;
}
//نكتب تفاصيل هذه الدالة خارج الصنف
int divisible();
};
inline int sample::divisible()
{
//لا يوجد باقي للقسمة
k=!(i%j);
return k;
}
int main()
{
int x,y;
cout<<"Enter X and Y \n";
cin>>x>>y;
sample s(x,y);
if (s.divisible())
cout<<x<<" Is divided by "<<y<<"\n";
else
cout<<x<<"Is Not Divided by"<<y<<"\n";
system("PAUSE");
return 0;
}

هذا مثال بسيط يقوم بطلب أدخال عددين من المستخدم ومن ثم يوضح ماإذا أمكن تقسيم العدد الأول على الثاني أو لا ..

ولكن الأهم ايضاحة هو الدالة الخطية حيث عرفنا داخل الصنف الدالة :

int divisible();

ومن ثم نكتب تفاصيل هذه الدالة خارج الصنف وذلك باستخدام مؤثر دقة الوصول Scope Resolution Operator وايضاً استخدمنا الكلمة المفتاحية inline كما يظهر هنا ::

inline int sample::divisible()
{
//لا يوجد باقي للقسمة
k=!(i%j);
return k;
}

وبقية تفاصيل البرنامج واضحة ان شاء الله ولا تحتاج لشرح ..

هذا هو الدرس باختصار عن استخدام الدوال الخطية Inline Functions ..

fa9l.gif

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

** استخدام المؤشر This :::

fa9l.gif

كل كائن يملك حق الوصول إلى عنوانه عن طريق مؤشر يدعى This .

يُستخدم المؤشر This بشكل ضمني ليشير أن الأعضاء تنتمي إلى كائن معين ، ويمكن استخدام المؤشر This بشكل صريح .

fa9l.gif

مثال :

#include <iostream.h>
#include <cstdlib>
using namespace std;
class test
{
private:
int x;
public:
test ( int =0);
void print()const;
};
test::test(int a)
{
x=a;
}
void test::print()const
{
cout<<"x = "<<x<<endl;
cout<<"This -> ="<<this->x<<endl;
cout<<"*this ="<<(*this).x<<endl;
}
int main()
{
test t(12);
t.print();
system("PAUSE");
return 0;
}

ملاحظات :

1- تم استخدام الدالة print() لطباعة قيمة المتغير x بشكل مباشر ، ثم بعد ذلك استخدمنا ترميزين مختلفين لطباعة x :

أ. معامل السهم ( -> ) مع المؤشر This .

ب. معامل النقطة ( . ) مع محتوى المؤشر ( *This ).

2- تم استخدام الأقواس مع محتوى المؤشر This ( *This ) ، لأن عامل النقطة له أولوية أعلى على عامل المحتوى ( * ) .

3- إذا لم يتم استخدام الأقواس مع محتوى المؤشر ( *This ) بحيث نضعها بهذا الشكل :

*this.x

فإنه يحدث خطأ قواعدي لأننا استخدمنا عامل النقطة مع المؤشر This .

** وهنالك استخدام آخر ومهم جداً للمؤشر This وهو تفعيل الاستدعاء المتتالي للدوال **

fa9l.gif

مثال : يبين هذا البرنامج إرجاع مرجع لكائن الصنف sample لتفعيل الاستدعاء المتتالي للدوال .

#include <iostream.h> 
#include <cstdlib>
using namespace std;
class sample
{
public:
int c;
sample &cube(int);
void show()
{
cout<<"Cube ="<<c<<endl;
}
};
sample &sample::cube (int a)
{
c = a*a*a;
return *this;
}
int main()
{
sample s;
s.cube(2).show();

system("PAUSE");
return 0;
}

هذا البرنامج طويل بعض الشيء .. سنشرح ماهو مهم .. :::

sample &cube(int);

هذا تعريف الدالة cube وهي لايجاد تكعيب أي عدد مدخل ( نوع الدالة مرجع كائن).

sample &sample::cube (int a)
{
c = a*a*a;
return *this;
}
int main()

وهذا هو كتابة تفاصيل الدالة كتبناها خارج الصنف حيث ان كل القيم من الدالة تمثل محتوى المؤشر This .

بعد ذلك والأهم وهو طريقة الاستدعاء المتتالي للدوال وهو كما ظهر في الدالة الرئيسية main().:

sample s;
s.cube(2).show();

فكما هو ملاحظ تم اشتقاق الكائن s من الصنف sample ومن ثم تم استدعاء الدالتين cube والدالة show بشكل متتالي ..

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

** التحميل الزائد للدوال Function Overloading :

fa9l.gif

وهو إمكانية إنشاء أكثر من دالة تحمل نفس الاسم ولكنها قد تختلف في نوعية المعاملات Parameters Types أو في عدد المعاملات Parameters No ، ولكل دالة الإجراء الخاص بها .

أي أن الدوال تشترك في اسمها ولكنها تختلف في شكلها ومضمونها .

fa9l.gif

مثال : برنامج يقوم بإجراء عملية الجمع باستخدام محمّلة بشكل زائد .

#include <iostream.h>
#include <cstdlib>
using namespace std;
class summation
{
public:
int a,b,c;
float x,y;
int sum(int,int);
float sum(float,float);
int sum(int,int,int);
};
int summation::sum(int a1,int b1)
{
return a1+b1;
}
float summation::sum(float x1,float y1)
{
return x1+y1;
}
int summation::sum(int a1,int b1,int c1)
{
return a1+b1+c1;
}
int main()
{
summation ob;
cout<<"Enter A,B,C \n";
cin>>ob.a>>ob.b>>ob.c;
cout<<"Enter X,y \n";
cin>>ob.x>>ob.y;
cout<<"sum1 ="<<ob.sum(ob.a,ob.b)<<endl;
cout<<"sum2 ="<<ob.sum(ob.x,ob.y)<<endl;
cout<<"sum3 ="<<ob.sum(ob.a,ob.b,ob.c)<<endl;

system("PAUSE");
return 0;
}

كما ظهر في هذا المثال لدينا ثلاثة دوال تحمل نفس الاسم :

int sum(int,int);
float sum(float,float);
int sum(int,int,int);

تظهر الدالةالأولى والثانية ان عدد الوسائط Parameters متساوي ولكنها تختلف في النوع حيث أن الأولى int والثانية float .

اما الدالة الثالثة فهي تختلف عنهم من حيث عدد الوسائط Parameters .

هذا باختصار عن ما يسمى بـ Function Overloading .

fa9l.gif

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

** التحميل الزائد للمؤثرات Operator Overloading ::

fa9l.gif

هو المقدرة على ربط مؤثر معين لدالة عضو في الصنف ويتم استدعاؤها عند تطبيق المؤثر على أحد كائنات الصنف .

* فائدته : مؤثر الجمع ( + ) نستطيع أن نقوم بتطبيقه على عددين صحيحين أو حقيقيين ولكن لا نستطيع استخدامه مع الكائنات إلا بعد تحميله تحميلاً زائداً .

ملاحظات :

1- لا ينبغي تغيير وظيفة المؤثر عند تحميله . مثلاً إذا قمنا بتحميل مؤثر الجمع فلا ينبغي استخدامه مع عملية أخرى مثل ( - , * , / ) ، لأن هذا الاستخدام يعتبر استخدام سيء لمفهوم التحميل الزائد للمؤثرات ويجعل من الصعب فهمه .

2- يمكن تحميل معظم المؤثرات الموجودة في لغة C++ بشكل زائد .

3-نستخدم الكلمة المفتاحية Operator عند القيام بتحميل مؤثر تحميلاً زائداً .

- والصيغة العامة لدالة التحميل الزائد للمؤثرات :

 datatype operator operatorSymbol ( Parameters)

حيث :

datatype = القيمة الراجعة من الدالة ( كائن ) .

operator = وهي كلمة مفتاحية Keyword .

operatorSymbol = وهو رمز المؤثر ( + , * , ...)

fa9l.gif

- المؤثرات التي يمكن تحميلها بشكل زائد في C++ وهي :

++ , --	// مؤثرات التزايد والتناقص
+ , - , * , / , ^ , % // المؤثرات الرياضية
= // المساواة
+= , -= , *= , /= , ^= , %= // المؤثرات المركبة
== , != , > , < , <= , >= // مؤثرات المقارنة
&& , || , ! // المؤثرات المنطقية
new , delete , new[ ] , delete[ ] //المؤشرين newوdelete

- المؤثرات التي لا يمكن تحميلها بشكل زائد :

 ?
.
::
->

* تعتبر محاولة تحميل أي مؤثر لا يمكن تحميله بشكل زائد خطأ قواعدي .

* تحميل مؤثري الجمع والإسناد ( + , = ) لجعل هذه الجملة صحيحة

 object2= object2 + object1

لا نستطيع أن نقوم بكتابة الجملة أعلاه بالشكل التالي :

 object2+=object1

إلا بعد تحميل المؤثر += بشكل صريح .

fa9l.gif

* مثال : على تحميل مؤثر التزايد ( ++ )

#include <iostream.h>
#include <cstdlib>
using namespace std;
class alpha
{
private:
int a;
public:
alpha()
{
a=1;
}
alpha (int);
void display();
alpha operator++();
};
alpha::alpha(int a1)
{
a=a1;
}
void alpha::display()
{
cout<<a<<endl;
}
alpha alpha::operator++()
{
++this->a;
return *this;
}
int main()
{
alpha a1,a2(12);
a1.display();
a2.display();
++a1;
a1.display();
++a2;
a2.display();
alpha a3;
a3=++a1;
a3.display();
a3=++a2;
a3.display();


system("PAUSE");
return 0;
}

هذا المثال يبين كيفية التعامل مع مؤثر التزايد ( ++ ) مع الكائنات بحيث تم تعريف الدالة التحميل الزائد داخل الصنف بالشكل التالي :

alpha operator++();

وكما يظهر أن الدالة لا تحتوي على أي وسائط Parameters ، وبالعادة دائما ما تكون مؤثرات التزايد والتناقص ( ++ , -- ) بدون وسائط ، ويظهر أن الدالة أيضاً ترجع كائن ، وتم كتابة تفاصيل الدالة خارج الصنف باستخدام مؤثر دقة الوصول Scope Resolution Operator كما بالشكل التالي :

alpha alpha::operator++()
{
++this->a;
return *this;
}

وسيتم شرح طرق كتابة دالة التحميل الزائد بعد توضيح مخرجات هذا البرنامج .

alpha a1,a2(12);
// هنا يطبع العدد 1
a1.display();
//وهنا يطبع العدد 12
a2.display();
//بعد ذلك تم تطبيق مؤثر التزايد على الكائن a1
++a1;
//وهنا سيطبع العدد 2
a1.display();
//وهنا تم تطبيق مؤثر التزايد على الكائن a2
++a2;
// يطبع القيمة 2
a2.display();
//تم اشتقاق كائن جديد
alpha a3;
//قمنا بتطبيق مؤثر التزايد على الكائن الأول تم إسناد قيمة الكائن a1
// في الكائن الجديد a3
a3=++a1;
//بعد ذلك طباعة الكائن الثالث التي تساوي العدد (3)
a3.display();
a3=++a2;
// طباعة العدد ( 14)
a3.display();

مؤثر الإسناد ( = ) يعرّف إذا كان لدينا حجز ديناميكي للذاكرة .

# يمكن لدالة التحميل الزائد أن ترجع كائن بثلاث طرق

1- استخدام مؤثر This :

alpha alpha :: operator ++()
{
++ this ->a;
return *this;
}

2- باستخدام كائن مؤقت Temporary Object :

alpha alpha :: operator ++()
{
alpha tmep;
temp.a=++a; // (Or) ++this->a;
}

3- باستخدام كائن من غير اسم Name Less Object

alpha alpha :: operator ++()
{
int aa;
aa=++a; \\ (Or) ++this ->a;
return aa;
}

هذه الطرق الثلاثة التي بالإمكان استخدامها مع مؤثري التزايد والتناقص ( ++ , -- ) ولكن مع مراعاة تغيير الإشارات بين المؤثرين .

fa9l.gif

** تحميل المؤثرات الثنائية ( + , - , * , / , ^ , % ) :

يتم تحميل المؤثرات الثنائية باستخدام دالة عضو ذات وسيطة واحدة أو باستخدام دالة غير عضو في الصنف مثلاً ( دالة صديقة ) بوسيطتين .

* مثال على تحميل مؤثر الجمع لإجراء عملية الجمع على كائنين باستخدام دالة تحميل عضو :

#include <iostream.h> 
#include <cstdlib>
using namespace std;
class add
{
private:
int a;
public:
add()
{
a=1;
}
add ( int a1)
{
a=a1;
}
void display()
{
cout<<a<<endl;
}
//الوسيطة عبارة عن كائن
add operator+(add p1)
{
this -> a=a+p1.a;
return *this;
}};
int main()
{
int x;
cout<<"Enter x";
cin>>x;
add add1,add2(x);
//يطبع القيمة الافتراضية الموجودة في دالة البناء وهي ( 1)
add1.display();
//يطبع القيمة المدخلة
add2.display();
add add3;
//وهنا الأهم حيث يجمع العدد ( 1 ) مع القيمة المدخلة من قبل المستخدم
add3=add1+add2;
//وهنا يطبع القيمة الجديدة
add3.display();
system("PAUSE");
return 0;
}

ويمكن أن تكون دالة التحميل الزائد دالة غير عضو كما ذُكر سابقاً ( مثلاً دالة صديقة Friend Function )وفي هذه الحالة يتم تعريفها داخل الصنف بالشكل التالي :

 friend add operator + (add,add)

وتفاصيلها تكتب خارج الصنف بالشكل التالي :

add operator ( add p1, add p2)
{
p1.a = p1.a + p2.a;
return p1;
}

وفي البرنامج الرئيسي يمكن أن نغير add3 إلى

 add3= operator +(add1,add2)

fa9l.gif

** تحميل المؤثرات المركبة (+= , -= , *= , /= , ^= , %= )

ذكرنا بأن تحميل أي مؤثر ثنائي مثل مؤثر الجمع لا يؤدي إلى تحميل المؤثرات المرتبطة به كـ ( += ) وبالتالي أي مؤثر مركب حتى نستطيع استخدامه مع الكائنات لابد من تحميله بشكل صريح .

* مثال يوضح طريقة تحميل المؤثر المركب +=

#include <iostream.h> 
#include <cstdlib>
using namespace std;
class meters
{
float m;
public:
meters()
{m=0;}
meters(float m1)
{
m=m1;
}
void show()
{
cout<<m<<endl;
}
//تعريف دالة التحميل الزائد على أنها دالة صديقة بوسيطتين
friend meters operator+=(meters ,meters );
};
meters operator+=(meters m1,meters m2)
{
m1.m+=m2.m;
return m1;
}
int main()
{
meters m1,m2(12.5);
meters m3(m2);
m1.show(); //0
m2.show();//12.5
m3.show();//12.5
//كما يظهر هنا التعامل المؤثر المركب =+
m2=operator+=(m2,m1);
m2.show();//12.5
m3=operator+=(m3,m2);
m3.show();//25
system("PAUSE");
return 0;
}

يظهر في هذا المثال طريقة تحميل دالة التحميل الزائد للمؤثر += وكيفية التعامل معها وهذا الحال ينطبق مع باقي المؤثرات المركبة ، وتم في هذا المثال تغيير بناء الدالة حيث تم هنا على أنها دالة صديقة Friend Function عكس ما تم عمله في الدرس الماضي .

fa9l.gif

** تحميل مؤثرات المقارنة ( == , != , > , < , <= , >= )

القيمة الراجعة من دالة التحميل الزائد لمؤثرات المقارنة هي عبارة عن قيمة منطقية boolean .

مثال على تحميل مؤثر (>)

#include <iostream.h>
#include <cstdlib>
using namespace std;
class comp
{
int a;
public:
comp ( int n )
{
a=n;
}
bool operator>(comp c)
{
return (a > c.a);
}
};
int main()
{
int x,y;
cout<<"enter x,y \n";
cin>>x>>y;
comp c1(x),c2(y);
if (c1>c2)
cout<<"c1 is greator";
else
cout<<"c2 is greator";

system("PAUSE");
return 0;
}

كما يظهر في هذا المثال يتم المقارنة بين الكائنين c1 و c2 ومن ثم طباعة القيمة الأكبر بينهما ...

وهذا باختصار عن ما يسمى بالتحميل الزائد للمؤثرات Operator Overloading .

fa9l.gif

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

** التحويل بين الأنواع Converting between types :

fa9l.gif

يوجد نوعان من البيانات :

1- الأنواع الأساسية مثل : int , float , double , …

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

وتوجد لدينا ثلاث أنواع من التحويلات :

1- من نوع أساسي إلى نوع معرف من قبل المستخدم .

2- من نوع معرف إلى نوع أساسي .

3- من نوع معرف إلى نوع معرف آخر من قبل المستخدم ( من كائن إلى كائن ) .

وسنأتي بالشرح مع الأمثلة لكل نوع من هذه الأنواع ..

fa9l.gif

أولا : من نوع أساسي إلى نوع معرف من قبل المستخدم .

مثلاً إذا كان لدينا متغير صحيح x وكائن من صنف معين m وكتبنا العبارة التالية m=x فهي تعني تحويل من نوع أساسي ( x ) إلى نوع معرف ( m ) .

مثال : هل يمكن تنفيذ البرنامج التالي ؟

class myclass 
{
/*------
------*/
}
main()
{
myclass c1;
int x;
c1=x;
}

الجواب بالطبع لا يمكن تنفيذ هذا البرنامج ؛ لأن العبارة :

c1=x

خاطئة !

ولجعل العبارة السابقة صحيحة لابد من معرفة الطريقة التي سوف يستخدمها المترجم لإنجاح هذه العملية والطريقة هي :

وجود دالة بناء ذات معامل ( وسيطة Parameter ) من نفس نوع المتغير المراد إسناده إلى الكائن .

مثال 2 : برنامج يقوم بالتحويل من نوع أساسي إلى نوع معرف .

#include <iostream.h>
#include <cstdlib>
using namespace std;
class meters
{
private:
int meter;
public:
meters()
{
meter=0;
}
meters(int m)
{
meter=m;
}
void display()
{
cout<<"meter="<<meter<<endl;
}};
int main()
{
meters m;
m.display();
int x;
cout<<"Enter x";
cin>>x;
m=x;
m.display();

system("PAUSE");
return 0;
}

فكما يظهر في هذا المثال لدينا المتغير x وهو من النوع int لذا قمنا بعمل دالة بناء ذات وسيطة من نفس المتغير x بالشكل التالي :

meters(int m)
{
meter=m;
}

فقط هذه كل العملية . عند تنفيذ البرنامج يطبع في البداية القيمة الموجودة في الكائن m ، ومن ثم يطلب البرنامج من المستخدم إدخال عدد صحيح ويحفظه في المتغير x ، بعد ذلك يقوم بإسناد أو مساواة القيمة الموجودة في المتغير x في الكائن m .. ولن يحدث حينها أي خطأ ..

fa9l.gif

2- التحويل من نوع معرف إلى نوع أساسي :

إذا كان لدينا متغير حقيقي float باسم ( y ) ، ولدينا كائن من صنف معين ( m ) وكتبنا العبارة التالية y=m فهي تعني تحويل نوع معرف ( m ) إلى نوع أساسي ( y ) .

مثال : هل يمكن تنفيذ البرنامج التالي :

class myclass 
{
/*------
------*/
}
main()
{
myclass c1;
float x=12.5;
x=c1;
}

هنا أيضاً لا يمكن تنفيذ هذا البرنامج ! ؛ لأن العبارة :

x=c1

خاطئة !

ولجعلها صحيحة لابد من تحميل النوع الأساسي float تحميلاً زائداً .

مثال 2 لبرنامج يقوم بالتحويل من نوع معرّف إلى نوع أساسي :

#include <iostream.h>
#include <cstdlib>
using namespace std;
class sample
{
float s;
public:
sample()
{
s=2.1;
}
void display()
{
cout<<s<<endl;
}
operator float()
{
return s;
}
};
int main()
{
sample ss;
ss.display();
float x;
cout<<"Enter x: ";
cin>>x;
x=ss;
ss.display();
cout<<x<<endl;

system("PAUSE");
return 0;
}

فكما ظهر لدينا في هذا المثال عندما قمنا بتحويل الكائن إلى نوع أساسي كما في الشكل التالي :

 x=ss;

وحتى تكون هذه العبارة صحيحة قمنا بتحميل النوع Float تحميلاً زائداً كما ظهر في الكود السابق :.

 operator float()
{
return s;
}

وبهذا تكون العملية صحيحة ، وتكون مخرجات البرنامج بالشكل التالي :.

sample ss;
//طباعة العدد 2.1
ss.display();
float x;
cout<<"Enter x: ";
cin>>x;
//هنا عملية التحويل
x=ss;
//طباعة العدد 2.1
ss.display();
//طباعة العدد 2.1
cout<<x<<endl;

فكما ظهر تم تحويل النوع المعرف إلى نوع معرف إلى نوع أساسي ، نأتي بعد ذلك للنوع الثالث والأخير وهو من كائن إلى كائن .

fa9l.gif

3- التحويل من نوع معرف إلى نوع معرف آخر ( كائن إلى كائن ) :

الصنف Class ||الكائن Object

c1 || class a

c2 || class b

فإذا كتبنا العبارة :

c1=c2

فهذه العملية معناها تحويل نوع معرف ( c1 ) إلى نوع معرّف آخر ( c2 ) .

** ملاحظة:

إذا كانت الكائنات c1 و c2 من نفس الصنف وكتبنا العبارة السابقة :

c1=c2

فهذه تعني نسخ محتويات الكائن c1 في الكائن c2 .

قبل أن نشرح طرق التحويل لابد من توضيح أمر مهم وهو عندما نكتب :

c2=c1

فذلك يعني أن :

c1 = كائن من صنف المصدر .

c2= كائن من صنف المخزن .

وتحويل نوع معرف إلى نوع معرف آخر يتم بإحدى طريقتين :

1- وجود دالة بناء ناسخة Copy Constructor في صنف المخزن وتستقبل وسيطة من نوع المخزن .

2-تحميل الصنف المحول إليه ( صنف المخزن ) تحميلاً زائداً داخل الصنف المصدر .

مثال : برنامج يقوم بتحويل صنف الكيلومترات والأمتار إلى سنتمترات باستخدام دالة بناء ناسخة .

#include <iostream.h>
#include <cstdlib>
using namespace std;
class kilometers
{
private:
int kmeter,meter;
public:
kilometers()
{
kmeter=meter=0;
}
kilometers(int k,int m)
{
kmeter=k;
meter=m;
}
void display()
{
cout<<kmeter<<endl;
cout<<meter<<endl;
}
int get_kmeter()
{
return kmeter;
}
int get_meter()
{
return meter;
}
};
class centimeters
{
int cent;
public:
centimeters()
{
cent=0;
}
void display()
{
cout<<cent<<endl;
}
centimeters (kilometers km) //Copy Constructor
{
int i;
i=(km.get_meter()*100000)+(km.get_kmeter()*100);
cent=i;
}};
int main()
{
int k,m;
cout<<"Enter kilometers :";
cin>>k;
cout<<"Enter Meters :";
cin>>m;
kilometers km1,km2(m,k);
km1.display();
km2.display();
centimeters c;
c.display();
c=km1;
c.display();
c=km2;
c.display();
system("PAUSE");
return 0;
}

المثال طويل بعض الشيء ، ولكن الموضوع وما فيه عبارة عن تحويلات بين القياسات باستخدام Copy Constructor ، وإذا ما أردنا تطبيق الحل باستخدام الطريقة الثانية (تحميل الصنف المحول إليه تحميلاً زائداً داخل الصنف المصدر ) نبدأ أولاً بـ Class centimeters ونحذف دالة البناء الناسخة منها ، ومن ثم نكتب بعده الصنف class kilometers ، ونحذف دوال الإرجاع get_ ... ونضيف دالة تحميل زائد داخل الصنف class kilometers ، بحيث بعد هذه التعديلات سيكون البرنامج بالشكل التالي :..

#include <iostream.h>
#include <cstdlib>
using namespace std;
class centimeters
{
public:
int cent;
centimeters()
{
cent=0;
}
void display()
{
cout<<cent<<endl;
}
};
class kilometers
{
private:
int kmeter,meter;
public:
kilometers()
{
kmeter=meter=0;
}
kilometers(int k,int m)
{
kmeter=k;
meter=m;
}
void display()
{
cout<<kmeter<<endl;
cout<<meter<<endl;
}
operator centimeters()
{
int i;

i= kmeter*100000+meter*100;
centimeters c;
c.cent =i;
}
};
int main()
{
int k,m;
cout<<"Enter kilometers :";
cin>>k;
cout<<"Enter Meters :";
cin>>m;
kilometers km1,km2(k,m);
km1.display();
km2.display();
centimeters c;
c.display();
c=km1;
c.display();
c=km2;
c.display();
system("PAUSE");
return 0;
}

ولمزيد من التفاصيل حول دالة البناء الناسخة Copy Constructor فالرجاء زيارة الموضوع الكبير لأستاذنا الفاضل romansy على هذا الرابط Advanced Function For Bigenners

fa9l.gif

تم تعديل بواسطه ماجددج
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

** الوراثة Inheritance

fa9l.gif

تعريف الوراثة : هي إمكانية أن يرث صنف ما الخصائص والعمليات الموجودة في صنف آخر ، مما يساعد على إعادة استخدام Reusability الأصناف التي تم إنشاؤها من قبل .

وبناء على هذا التعريف فإنه يمكن تحديد مفهومين جديدين وهما :

1- صنف القاعدة ( الأساس Or الموروث ) base class : وهو الصنف الذي يحوي البيانات والعمليات المراد توريثها لصنف آخر .

2- الصنف المشتق ( الوارث ) Derived class : وهو الصنف الوارث لخصائص وعمليات الصنف الأساس .

fa9l.gif

# أنواع الوراثة Inheritance Types :

توفر لغة C++ ثلاث أنواع من الوراثة حيث يحدد نوع الوراثة درجة الوصول للبيانات والعمليات الموجودة في صنف الأساس من خلال الصنف المشتق . والأنواع هي :

1- الوراثة الخاصة private Inheritance :

عندما يرث صنف مشتق صنف الأساس وكان نوع الوراثة خاص فإنه كل البيانات والعمليات الموجودة في صنف الأساس تصبح خاصة الصنف المشتق .

2-الوراثة المحمية protected Inheritance :

وفي هذا النوع تصبح كل بيانات وعمليات صنف الأساس محميّة بالصنف المشتق .

3- الوراثة العامة public Inheritance :

في هذا النوع يتم توزيع البيانات والعمليات كما يلي :

أ- المحمي protected في صنف الأساس base class يصبح محمي في الصنف المشتق .

ب- العام public في صنف الأساس يصبح عام في الصنف المشتق .

ج- الخاص لا يورّث أبدا ( البيانات الخاصة لا تورّث أبداً )! ..

ويمكن توضيح ما سبق من خلال هذا الجدول :.

post-58588-1203089207_thumb.jpg

تشكل الوراثة هيكل هرمي حيث يمثل صنف الأساس قمة الهرم فمثلاً .::

post-58588-1203089229_thumb.jpg

- الصيغة العامة للوراثة :

لجعل الصنف derived يرث الصنف Base :

 class derived : InheritanceType Base

ومثال ذلك :

#include <iostream.h>
#include <cstdlib>
using namespace std;

class B
{
int i;
public:
void set_i(int);
int get_i();
};
class D:public B
{
int j;
public:
void set_j(int);
int multi();
};
void B::set_i(int n)
{i=n;}
int B::get_i()
{
return i;
}
void D::set_j(int m)
{
j=m;}
int D::multi()
{
return get_i()*j;
}
int main()
{
int a,b;
cout<<"Enter A,B \n";
cin>>a>>b;
D ob;
ob.set_i(a);
ob.set_j(b);
cout<<"Multi ="<<ob.multi()<<endl;

system("PAUSE");
return 0;
}

فكما يظهر في هذا المثال البسيط الذي يضرب عددين مدخلين من قبل المستخدم ، في هذا المثال لدينا صنفين ( Class B, Class D ) ، وأن الصنف D يرث وراثة عامة Public من الصنف B كما ظهر في الشكل التالي :.

  class D:public B

ومن خلال هذه العلاقة فإنه عندما نشتق كائن من الصنف D فإنه بإمكاننا أن نصل لكافة المتغيرات والدوال الموجودة في المستوى ( Protected , public ) في الصنف B ، ويوجد في الصنف D دالة ضرب العددين كما في الشكل التالي :.

int D::multi()
{
return get_i()*j;
}

فكما يظهر لدينا الدالة get_i() الموجودة في الصنف B تم التعامل معها هنا في الصنف D بدون أي إضافات .

fa9l.gif

* دوال البناء والهدم تحت الوراثة Constructor And Destructor Functions Under Inheritance :

إن كلاً من الصنف الوارث والصنف الموروث يمكن أن يمتلكا دوال بناء ودوال هدم .

# ملاحظات :

1- دالة بناء الصنف الموروث تنفذ قبل دالة بناء الصنف الوارث .

2- دالة هدم الصنف الوارث تنفذ قبل دالة هدم الصنف الموروث .

3- لا يمكن توريث دوال البناء والهدم من الصنف الأساس إلى الصنف المشتق .

4- يتم إرسال المعاملات لدالة بناء الصنف الموروث من خلال دالة بناء الصنف الوارث باستخدام مهيء العضو ( : ) .

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

#include <iostream.h>
#include <cstdlib>
using namespace std;
class point
{
public:
point ( int =0,int =0);
~point();
protected:
int x,y;
};
point::point(int a,int b)
{
x=a;
y=b;
cout<<"Point Constructor ["<<x<<','<<y<<']'<<endl;
}
point::~point()
{
cout<<"Point Destructor:["<<x<<','<<y<<']'<<endl;
system("PAUSE");
}
class circle:public point
{
public:
circle(double r=0,int x=0,int y=0);
~circle();
private:
double radius;
};
circle::circle(double r,int a,int b):point(a,b)
{
radius=r;
cout<<"Circle Constructor : radius is:"<<radius<<'['
<<x<<','<<y<<']'<<endl;
}
circle::~circle()
{
cout<<"Circle Destructor : Radius is :"<<radius
<<'['<<x<<','<<y<<']'<<endl;
system("PAUSE");
}
int main()
{
{
point p(11,22);
}
circle circle1(4.5,72,29);
circle circle2(10,5,5);
system("PAUSE");
return 0;
}

كما يظهر في هذا المثال لدينا دالة البناء Point والصنف circle الذي يرث من الصنف Point وراثة عامة Public كما يظهر في الشكل التالي :

 class circle:public point

الأهم في هذا الكود هو أولوية استدعاء الدوال ، في الدالة الرئيسية main() لدينا الكود التالي :

{
{
point p(11,22);
}
circle circle1(4.5,72,29);
circle circle2(10,5,5);
system("PAUSE");
return 0;
}

أول شيء لدينا الكائن P في مجال معين ( بين أقواس )

{
point p(11,22);
}

في هذه الحالة يقوم باستدعاء دالة البناء point ومن ثم دالة الهدم مباشرة قبل الخروج من هذا المجال بحيث تكون المخرجات بالشكل التالي :.

Point Constructor [11,22]
Point Destructor:[11,22]

بعد ذلك لدينا اشتقاق للكائن circle1 ، وكما ذكرنا سابقاً في الملاحظات ( ملاحظة رقم 1) ، حيث يتم في البداية تنفيذ دالة البناء point أولاً ومن ثم دالة البناء لـ circle ، وكذا الحال مع الكائن circle2 بحيث تكون المخرجات بالشكل التالي :.

Point Constructor [72,29]
Circle Constructor : radius is:4.5[72,29]
Point Constructor [5,5]
Circle Constructor : radius is:10[5,5]

( لاحظ هنا يتم أولاً تنفيذ دوال البناء كلها قبل تنفيذ أي دالة هدم قبل الخروج من المجال المحدد ) .

بعد ذلك يتم استدعاء دوال هدم الصنف الوارث قبل الصنف الموروث بترتيب معاكس بحيث الناتج النهائي للبرنامج بكامل مخرجاته ستكون على النحو التالي ::..

Point Constructor [11,22]
Point Destructor:[11,22]
Point Constructor [72,29]
Circle Constructor : radius is:4.5[72,29]
Point Constructor [5,5]
Circle Constructor : radius is:10[5,5]
Circle Destructor : Radius is :10[5,5]
Point Destructor:[5,5]
Circle Destructor : Radius is :4.5[72,29]
Point Destructor:[72,29]

fa9l.gif

* الوراثة المتعددة Multiple Inheritance :

تسمح لغة C++ لصنف ما أن يرث أكثر من صنف ، وهذا النوع من التوارث يتحقق بطريقتين :

1- الصنف الوارث يمكن أن يُستخدم كـصنف موروث من قبل صنف وارث آخر ويمكن توضيح ذلك بالهرمية التالية :

post-58588-1203089266_thumb.jpg

2- الصنف الوارث يمكن أن يرث أكثر من صنف موروث .

والصيغة العامة للتوارث في هذه الحالة هي :

class derived :inheritanceType NameOfBaseClass1, inheritanceType NameOfBaseClass2, . . . , inheritanceType NameOfBaseClassN
{
Class Body
};

ويمكن تمثيلها كما يظهر في الشكل التالي :.

post-58588-1203089275_thumb.jpg

# ملاحظات :

1- في حالة وراثة عدّة أصناف موروثة فإن دوال البناء يتم تنفيذها من اليسار إلى اليمين والعكس بالنسبة لدوال الهدم :

post-58588-1203089283_thumb.jpg

2- يتم إرسال المعاملات لدالة بناء الصنف الموروث ( الأصناف الموروثة ) من خلال دالة بناء الصنف الوارث .

مثال : على التوارث المتعدد ( الطريقة رقم 2 من الصورة السابقة ) :

#include <iostream.h>
#include <cstdlib>
using namespace std;
class B1
{
int a;
public:
B1(int x)
{
a=x;
}
int get_a()
{return a;
}
};
class D1:public B1
{
int b;
public:
D1(int x,int y):B1(y)
{
b=x;
}
int get_b()
{
return b;
}
};
class D2:public D1
{
int c;
public:
D2(int x,int y,int z):D1(y,z)
{
c=x;
}

void show()
{
cout<<get_a()<<"\n"<<get_b()<<"\n"<<c<<endl;
}};
int main()
{
int a,b,c;
cout<<"Entera,b,c \n";
cin>>a>>b>>c;
D2 ob(c,b,a);
ob.show();
system("PAUSE");
return 0;
}

في هذا المثال ستكون هرمية التوارث :

1- B1 .	   2-D1 .	 3- D2.

بحيث لو كانت المدخلات :

1

2

3

سيكون الناتج أيضاً كما هو في المدخلات :

1

2

3

وهذا المثال آخر على الطريقة الثانية ( الشكل رقم 1 من الصورة السابقة )

#include <iostream.h>
#include <cstdlib>
using namespace std;
class B1
{
int a;
public:
B1(int x)
{
a=x;}
int get_a()
{return a;}};
class D1
{
int b;
public:
D1(int x)
{
b=x;}
int get_b()
{return b;}};
class D2:public D1,public B1
{
int c;
public:
D2(int x,int y,int z):D1(y),B1(z)
{c=x;}
void show()
{
cout<<get_a()<<"\n"<<get_b()<<"\n"<<c<<endl;
}};
int main()
{
int a,b,c;
cout<<"Entera,b,c \n";
cin>>a>>b>>c;
D2 ob(c,b,a);
ob.show();
system("PAUSE");
return 0;
}

وهذا المثال يوضح كيفية استدعاء دوال البناء والهدم في حال وجود عدّة أصناف موروثة :

#include <iostream.h>
#include <cstdlib>
using namespace std;
class B1
{
public:
B1()
{
cout<<"B1 Construcor\n";
}
~B1()
{
cout<<"B1 Destrucor\n";
system("PAUSE");
}
};
class B2
{
public:
B2()
{
cout<<"B2 Construcor\n";
}
~B2()
{
cout<<"B2 Destrucor\n";
system("PAUSE");
}
};
class D:public B1,public B2

{
public:
D()
{
cout<<"D Construcor\n";
}
~D()
{
cout<<"D Destrucor\n";
system("PAUSE");
}
};
int main()
{
B1 ob1;
{
B2 ob2;
}
D ob;
system("PAUSE");
return 0;
}

يجب التنويه بنقطة ذكرناها سابقاً وهي عند يتم أولاً تنفيذ دوال البناء كلها قبل تنفيذ أي دالة هدم قبل الخروج من المجال المحدد ، وسبق شرح هذه النقطة سابقاً ، وستكون مخرجات هذا البرنامج بالشكل التالي ::.

B1 Construcor
B2 Construcor
B2 Destrucor
B1 Construcor
B2 Construcor
D Construcor
D Destrucor
B2 Destrucor
B1 Destrucor
B1 Destrucor

fa9l.gif

* الصنف الموروث الوهمي Virtual Base Class :

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

post-58588-1203089289_thumb.jpg

في هذه الحالة يتم توارث الصنف base1 مرتين في الصنف derived3 مرتين ، مرة من خلال dervied1 ومرة أخرى من خلال الصنف dervied2 .

مما يؤدي إلى ازدواجية عند الوصول أو إرسال المعاملات إلى أعضاء الصنف base1 وفي هذه الحالة يظهر الاستفسار التالي :

- هل يتم إرسال المعاملات إلى الصنف base1 عن طريق derived1 أو عن طريق derived2 ؟

ولحل هذه المشكلة "الازدواجية" توجد في لغة C++ آلية تعمل على إيجاد نسخة واحدة من الصنف الوارث derived3 في الصنف الموروث base1 وهذه الآلية تعرف بالصنف الموروث الوهمي .

* مثال على الصنف الموروث الوهمي :

#include <iostream.h>
#include <cstdlib>
using namespace std;
class base
{
public:
int i;
};
class derived1:virtual public base
{
public:
int j;
};
class derived2:virtual public base
{
public:
int k;
};
class derived3:public derived1,public derived2
{
public:
int protect()
{
return i*j*k;}};

int main()
{
derived3 ob;
cout<<"Enter i,j,k\n";
cin>>ob.i>>ob.j>>ob.k;
cout<<"Result = "<<ob.protect()<<endl;
system("PAUSE");
return 0;
}

ويلاحظ في هذا الكود هو إضافة الكلمة المفتاحية Virtual في كل من ::..

class derived1:virtual public base

class derived2:virtual public base

والباقي لا جديد فيه ..

fa9l.gif

fa9l.gif

إلى هنا نأتي وإياكم إلى نهاية هذه الدورة المبسطة تطلعك بإذن الله على أهم المواضيع الخاصة بما يعرف بـ ( البرمجة غرضية التوجه object oriented programming ) ، كل أملي بإذنه تعالى أن تنال هذه الدورة استحسانك ورضاك بعد رضاه سبحانه وتعالى ، فما كان من خطأ فمن نفسي والشيطان ، وما كان من صواب فمن الله سبحانه وتعالى هو نعم المولى ونعم النصير ..

وفق الله الجميع لما يحب ويرضى .. ولا تنسوني من دعائكم لي في ظهر الغيب بالتوفيق والفلاح في الدنيا والآخرة ..

دمتم في رعاية الله وحفظـــه ...

أخوكم : ماجد ..

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

اول شي اخوي

جزاك الله الف خير ووفقك الله دنيا وآخرة

وجعلة في ميزاان حسناتك

اللهم آمين

اخوي انا عندي هدف وهو تصميم نظام تشغيل على بيئة اليونكس

وانا مبتدى في البرمجة وقبلت بالجامعة ولله الحمد

السوال

انا الي اعرفة ال c ما تستخدم البرمجة غرضية التوجة ؟صح كلامي والا انا غلطان؟

هل بالامكان تصميم نظام تشغيل عن طريق السي ++؟ وباي لغة تصمم انظمة التشغيل؟

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

أخي ماجد مشكور جداً على الشرح الأكثر من رائع

و بالنسبة للأخ almstshar2 فإذا كنت في بداية حياتك البرمجية فلا أنصحك ان تبدأ بتصميم نظام تشغيل!!!!!!!!!!!!!!!

لأن الأمر ليس بالبساطة التي تتصورها

و على كل يوجد في منتدى تصميم التطبيقات مقالات تتحدث عن انظمة التشغيل و طرق عملها و برمجتها و كتب و افكار .... الخ

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

ماذا اقوول ؟؟؟

كلمه مشكوووووور او واصل ابداع او ... او ... او ...

لا تكفي لكي اصف هذا الابداع الرائع

بصراحه افضل من كذه شرح ...... ما فيش

انت اخي الكريم رائع بكل معنى الكلمه

تقبل خالص حبي وتقديري على كل هذا المجهود الرائع

الذي اذا دل على شيئ دل على انك انسان كريم تحب لغيرك مثل ما تحب لنفسك

بالتوفيق والى الامام دوما

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

مشكووور اخوي كفيت ووفيت ^_^

الله يوفقك مررره استفدت من الموضوع

واكرر شكري لك =)

تقبل مروري ...

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

ماشاء الله عليك ،، والله أعجز عن شكرك !!

فعلاً أول مره أفهم البرمجة غرضية التوجيه بهذا الشكل !! :thumb_up:

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

لي طلب صغير لغاية ، أرجو منك أخي الكريب كتابة برنامج بسيط ( مثل برنامج لحساب مساحة المستطيل أو الدائرة ) إن كان يصلح للغرض التالي :

أريد منك كتابة كود البرنامج مره بأسلوب البرمجة الإجرائية ، ومره بأسلوب البرمجة غرضية التوجيه OOP .

أشكرك مجدداً ، وأنتظر ردك ...

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

بسم الله ما شاء الله

موضوع شامل ورائع

جزاك الله خيرا اخى

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .