هو تابع عضو في الصف يحمل املواصفات التالية : له نفس اسم الصف . يستدعى ضمنيا عند إنشاء الغرض . ليس له قيمة.

Download Report

Transcript هو تابع عضو في الصف يحمل املواصفات التالية : له نفس اسم الصف . يستدعى ضمنيا عند إنشاء الغرض . ليس له قيمة.

Slide 1

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 2

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 3

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 4

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 5

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 6

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 7

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 8

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 9

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 10

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 11

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 12

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 13

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 14

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 15

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 16

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 17

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 18

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 19

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 20

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 21

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 22

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 23

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 24

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 25

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 26

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 27

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 28

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 29

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 30

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 31

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 32

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 33

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 34

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 35

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 36

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 37

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 38

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 39

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 40

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 41

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 42

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 43

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 44

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 45

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 46

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬


Slide 47

‫هو تابع عضو في الصف يحمل املواصفات التالية ‪:‬‬
‫له نفس اسم الصف ‪.‬‬
‫يستدعى ضمنيا عند إنشاء الغرض ‪.‬‬

‫ليس له قيمة معادة أي ليس له نمط إرجاع ‪.‬‬
‫يمكن أن نقوم بإجراء ‪ Overloading‬له ‪.‬‬
‫يتم التصريح عنه في قسم الـ ‪ public‬وإن تم التصريح عنه في قسم الـ ‪ private‬فإنه‬
‫سيحصل مشكلة عند إنشاء غرض ما ‪.‬‬

‫في الباني نقوم بإعطاء قيمة ابتدائية للمتحوالت ‪.‬‬

‫يوجد باني افتراض ي ‪ default constructor without parameters‬مبني‬
‫ضمنيا في اللغة وال يقوم بأي ش ي فإذا كنا نريد تعديله فإننا نعيد كتابته من جديد‪.‬‬
‫يمكن عمل ‪ overloading‬له وبالتالي يمكن إنشاء أكثر من باني وكل باني يأخذ‬
‫عدد معين من الـ ‪. parameters‬‬
‫يتم استدعاء الباني ضمنيا عند إنشاء غرض أو عند إجراء عملية ‪ new‬أي يمكننا‬
‫القول بأنه يتم استدعاء الباني ضمنيا عند إنشاء غرض سواء ستاتيكيا أو ديناميكيا‪.‬‬

‫هنا يتم استدعاء الباني االفتراض ي املوجود في اللغة الذي ال يأخذ متحوالت‪.‬‬

‫هنا يتم استدعاء الباني الذي تم كتابته داخل الصف ‪.‬‬

‫هذه طريقة أخرى في إسناد القيم إلى متحوالت الصف ضمن الباني وتدعى هذه‬
‫الطريقة بـ ‪. member initialization lists‬‬

‫عندما نضع القوسين )( عند بناء الغرض فإننا هنا نطلب استدعاء الـ ‪default‬‬
‫‪. constructor‬‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن النوع األول وهو الباني االفتراض ي واآلن سوف نتكلم عن الباني‬
‫الناسخ‪.‬‬
‫إذا لم يعرف هذين البانيين من قبل املبرمج فإنها تكون معرفة تلقائيا عند تعريف‬
‫الصف‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الحظ أن الباني الناسخ له معامل دخل واحد يمرر بالعنوان الثابت حتى ال يتم التعديل‬
‫عليه والهدف من الباني الناسخ هو إنشاء غرض مماثل للغرض الذي يتم تمريره للباني‬

‫الناسخ‪.‬‬
‫إذا مهمة الباني الناسخ هو إنشاء نسخة طبق األصل لغرض ما يتم تمرير هذا األخير‬

‫بالعنوان الثابت كي ال يتغير ‪.‬‬
‫يوجد باني ناسخ افتراض ي ‪ ،‬ولكن إعادة كتابة الباني الناسخ تعطينا قدرة أكبر على التحكم‬

‫في البرنامج ‪.‬‬

‫جرب نفس املثال السابق ولكن بدون كتابة الباني‬
‫االفتراض ي الذي ال يحوي معامالت ‪ ..‬ماذا يحدث ؟‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫الباني الناسخ يتم استدعاءه في إحدى الحاالت الثالث التالية ‪:‬‬
‫عندما يتم تمرير ‪ object‬لتهيئة ‪ object‬آخر وهذا كما في األمثلة السابقة ‪.‬‬

‫عندما يتم تمرير ‪ object‬بالقيمة ‪ ،‬هنا يتم أخذ نسخة من الغرض للتعامل معه داخل التابع كي‬
‫ال تتعدل النسخة األساسية )تذكر التمرير بالقيمة ‪.(by value‬‬

‫عندما يتم إرجاع غرض من تابع ‪ ،‬هنا أيضا يتم أخذ نسخة من الغرض من داخل التابع ليتم رده‬
‫للنطاق الخارجي ‪.‬‬

‫إن استخدام إشارة اإلسناد بين األغراض تؤدي إلى استدعاء الباني الناسخ املوجود في‬

‫النظام دوما ‪.‬‬
‫يتم نسخ جميع قيم متحوالت الغرض املوجود في القسم األيمن من عملية اإلسناد إلى‬

‫متحوالت الغرض املوجود في القسم األيسر من عملية اإلسناد على التتالي ‪.‬‬
‫ال ينصح باستخدام عملية اإلسناد لنسخ قيم غرض إلى غرض آخر وخاصة عندما يحوي‬

‫الغرض على مؤشرات ‪ .‬سنتكلم عن هذا األمر بعد قليل ‪.‬‬

‫إن جميع ما تكلمنا عنه سابقا يندرج تحت الـ ‪. Shallow copy‬‬

‫الباني الناسخ في لغة الـ ‪ C++‬يستخدم الـ ‪. Shallow copy‬‬
‫الـ ‪ Assignment operator‬أيضا يستخدم الـ ‪. Shallow copy‬‬

‫في الـ ‪ Shallow Copy‬في حال كان الصف يحوي على مؤشرات فإن املؤشر املوجود في‬
‫الغرض األساس ي واملؤشر املوجود في النسخة يصبحان يشيران إلى نفس املكان في الذاكرة ‪،‬‬

‫ففي حال تم تحرير مكان الذاكرة هذا من قبل أحد األغراض فإن هذا يسبب مشاكل كبيرة‬
‫بالنسبة للغرض اآلخر ‪ ،‬إذا ما الحل ؟‬

‫إذا كان الصف يحوي على مؤشرات فإنه يجب علينا كتابة ‪Deep Copy‬‬

‫‪.Constructor‬‬
‫في ‪ Deep Copy Constructor‬نقوم بإنشاء مواقع جديدة في الذاكرة ونجعل‬

‫املؤشرات تشير إليها وبعدها ننقل القيم املوجودة في الغرض األصل إلى النسخة الجديدة‪.‬‬
‫هذه األمور يجب الحذر منها وهي التي تتعلق بالحجز الديناميكي في الذاكرة عن طريق‬

‫التعليمتان ‪ new‬و ‪ delete‬واللتان تتعلقان باملؤشرات ‪.‬‬
‫نقوم بكتابة ‪ Body of Deep Copy Constructor‬في الباني الناسخ الذي تكلمنا‬

‫كل صف له على األقل بانيان موجودين ضمنيا‪:‬‬
‫الباني التلقائي ‪ default constructor‬وهو بالشكل ) (‪Circle‬‬
‫الباني الناسخ ‪ copy constructor‬وهو بالشكل )‪Circle (const Circle & c‬‬

‫تكلمنا سابقا عن البانيين السابقين ‪.‬‬
‫ولكن يوجد أيضا ما يسمى بالهادم والذي يعمل عكس عمل الباني فينبغي أن تكون‬
‫مهمته تحرير الذاكرة املحجوزة بشكل ديناميكي‪.‬‬

‫له نفس اسم الصف ‪.‬‬

‫نميزه عن الباني بأنه مسبوق باإلشارة ~ أي يكون }‪~Class_name{…..‬‬
‫ال يوجد وسطاء دخل وال يوجد ‪. return type‬‬
‫ال يمكن عمل ‪ overloading‬له ‪.‬‬
‫يستدعى تلقائيا عند موت الغرض أي عند انتهاء فترة حياته ‪.‬‬
‫يوجد هادم موجود مسبقا في اللغة ولكن يمكن أيضا كتابته بأنفسنا مما يؤمن قدرة‬
‫أكبر على التحكم في ذاكرة البرنامج وخاصة أثناء التعامل مع املؤشرات ‪.‬‬

‫آخر غرض تم إنشاءه هو أول غرض يتم حذفه ولكن يتم ذلك وفق قيود معينة ‪.‬‬

‫نهتم أوال بإنشاء األغراض العامة وفقا لترتيب ورودها ‪.‬‬
‫تذكر أنه بعد الخروج من ‪ local scope‬يتم تدمير الغرض وبالتالي يتم استدعاء‬
‫الهادم تلقائيا ‪.‬‬
‫بالنسبة لألغراض التي صرح على أنها ‪ static‬تذكر أنها تنشأ مرة واحدة فقط وأنه‬
‫يتم تدميرها بعد االنتهاء من الـ ‪ main‬أو الوصول إلى ‪. exit‬‬
‫بشكل عام يتم استدعاء الهادم وفق ترتيب معاكس الستدعاء الباني ‪.‬‬

‫أحيانا قد نضطر إلنشاء غرض ثابت مثال‬

‫)‪. Ratio r (22,7‬‬

‫الغرض الثابت ال يمكن تعديله ‪.‬‬
‫يتم التصريح عنه بالشكل التالي ‪const class_name object_name( ..) :‬‬
‫إن أي محاولة لتعديل الغرض الثابت يعطي ‪ Compiler Error‬حتى إن لم تكن‬
‫الـ ‪ data members‬قد تم التصريح على أنها ‪. const‬‬
‫الغرض الثابت ال يستطيع استدعاء الـ ‪ method‬في صف ؟ حيث يظهر لدينا‬
‫‪. Compiler Error‬‬

‫عند تعريف غرض على أنه ثابت فإنه يحظر‬
‫علينا استخدام توابع الصف ‪ .‬إذا ما الحل ؟‬

‫قم بالتصريح عن التوابع األعضاء في الصف‬
‫على أنها ثوابت أيضا ‪.‬‬

‫تذكر أن األغراض الثابتة ال تستطيع التعامل‬
‫إال مع التوابع األعضاء الثابتة‪.‬‬

‫ال يمكن تغيير قيم الـ ‪data members‬‬
‫ضمن ‪.const method‬‬

‫تذكر القواعد التالية ‪:‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض الغير ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫األغراض الثابتة ال تستطيع استدعاء توابع أعضاء غير ثابتة ‪.‬‬
‫األغراض ثابتة تستطيع استدعاء توابع أعضاء ثابتة ‪.‬‬

‫إذا كان لدينا صف يحوي على ‪ data member‬تم التصريح عنه على أنه‬
‫‪. const‬‬
‫نحن نعلم أنه ال يمكن إعطاء قيم ابتدائية للـ ‪ data member‬مباشرة عند‬
‫تعريفها في الصف‪ ،‬بل كنا نقوم بعملية التهيئة في الباني ‪.‬‬
‫ولكن هنا ستعتبر عملية التهيئة في الباني كأنها تعديل على الـ ‪const data‬‬
‫‪ member‬وهذا سيؤدي بدوره إلى ‪. Compiler Error‬‬
‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫إذا ما هو املكان املناسب كي نقوم بإعطاء ‪ const data members‬قيمها ؟؟‬

‫ما رأيك لو كان الحل بأن نصرح عن الباني على أنه ‪ const‬كما فعلنا في التوابع‬
‫األعضاء في املثال السابق ؟‬
‫هذا خاطئ تذكر اآلتي ‪ :‬إن البواني والهوادم ال يمكن أن تكون ‪. const‬‬

‫إذا ما الحل ؟‬
‫الحل هو استخدام ‪ Member initialization lists‬وهي الطريقة الثانية في كتابة الباني‪.‬‬

‫وظيفة كتابة صف للتعبير عن العدد الكسري‬
‫وتضمين العمليات التالية ‪:‬‬
‫جمع وطرح عددين كسريين‬
‫ضرب وقسمة عددين كسريين‬
‫مقارنة عددين كسريين‬
‫طباعة العدد الكسري‬