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

++c ... المحاضرة ( 3 )

مغلق
بدأه BjarneStudent في 4 نوفمبر 2007 · 14 رد · 7,312 مشاهدة · في المواضيع والدروس
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

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

بسم الله وبه نستعين

سوف نتناول في هذه المحاضرة المواضيع التالية :

1- الأصناف والكائنات وبيانات الأعضاء ودوال الأعضاء.

2- تعريف صنف مع دالة عضو واحدة.

3- تعريف دالة عضو بوسيط واحد.

4- تطبيق لغة الـ UML على أمثلة هذه المحاضرة.

في الفصل السابق قمنا بشرح برامج تقوم بعرض رسالة وأخذ بيانات من المستخدم وإجراء بعض العمليات الحسابية

عليها وإخراج النتائج, في هذا الفصل سوف نقوم بالبرمجة الكائنية وإنشاء برامج تقوم من خلالها بتشغيل المفاهيم

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

العبارات فيها, ولكننا في هذه المحاضرة سوف نبتدي معكم في عزل هذه المهمات عن الدالة الرئيسة وتعليبها لإتاحة

استخدامها في برامج أخرى.

الأصناف والكائنات وأعضاء البيانات ودوال الأعضاء

أخذنا في الفصل المحاضرة الماضية مثال السيارة, حيث قلنا أننا عند الضغط على دواسة البنزين فإن سرعة السيارة سوف تزيد

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

عند كتابة الأكواد, كل مهمة سوف تسدل لدالة لتقوم بها ( مثل دالة الـ main كما اوضحنا في الماضرة الثانية ). الدالة تصف

الميكانيكيات التي تصف مهمتها وهي تقوم أيضا بإخفاء كل هذا عن مستخدمها.

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

ذلك بدالة العضو. يحتوي كل صنف على دالة واحدة أو أكثر. على سبيل المثال, الصنف الذي يمثل حساب بنكي لأحد العملاء يحتوي على

دالة عضو لإيداع مبلغ من المال, وأخرى للسحب من الحساب وآخرى للإستعلام عن الرصيد الحالي.

بعد ذلك سوف تقوم بإنشاء كائن. لماذا نقوم بإنشاء كائن؟ كلي نجيب على هذا السؤال سف نصف الصنف بورقة التصميم المرسومة

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

بالطبع لا يمكنك ذلك. فلكي تستفيد من ذلك التصميم, يجب عليك إنشاء سيارة فعلية من هذا التصميم وهذا هو ما يمثل الكائن, والعلاقة

بين ورقة التصميم للسيارة والسيارة كالعلاقة بين الصنف والكائن. ولهذا سميت لغة الـ C++ بلغة الكائن الموجة نسبة ً لهذا العملية.

ايضا, يمكننا أن ننشيء عدة سيارات من هذا التصميم, كذلك يمكننا أن ننشيء عدة كائنات من نفس الصنف.

عندما تقود السيارة وتدوس على دواسة البنزين, أنت تقوم بإرسال رسالة إلى السيارة لتؤدي هذه المهمة ( قيادة السيارة وزيادة السرعة )

, بالمقابل في هذا البرنامج أنت ترسل رسائل للكائن تعرف بمناداة دالة العضو للكائن لكي يقوم بمهمته. وهذه العملية تسمى " طلب الخدمة

من الكائن ".

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

, سعة التانك, لون السيارة. هذه الأشياء جزء من التصميم الهندسي للسيارة , فهي مربوطة بالسيارة عند عملية صيانتها ولا يمكن اهمالها.

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

الخصائص تكون معرفة بـ " أعضاء بيانات الصنف " في لغة الـ c++.

نضرة على أمثله هذا الفصل

سوف نتناول في هذه الحاضرة امثله , عبارة عن برامج صغيرة لتوضيح التقنيات الجديدة.

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

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

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

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

الرابع وتخزين البيانات يكون في الفصل السابع.

تعريف صنف مع دالة عضو واحدة

المثال الأول

 



1  // Fig. 3.1: fig03_01.cpp
2  // Define class GradeBook with a member function displayMessage;
3  // Create a GradeBook object and call its displayMessage function.
4  #include <iostream>
5  using std::cout;
6  using std::endl;
7
8  // GradeBook class definition									   
9  class GradeBook													 
10  {																   
11  public:															 
12	 // function that displays a welcome message to the GradeBook user
13	 void displayMessage()											
14	 {																
15		cout << "Welcome to the Grade Book!" << endl;				 
16	 } // end function displayMessage								 
17  }; // end class GradeBook										   
18
19  // function main begins program execution
20  int main()
21  {
22	 GradeBook myGradeBook; // create a GradeBook object named myGradeBook 
23	 myGradeBook.displayMessage(); // call object's displayMessage function
24	 return 0; // indicate successful termination
25  } // end main

يتكون هذا البرنام من صنف دفتر الدرجات GradeBook الذي من خلالة يقوم المعلم بمتابعة نتائج الإختبارات. يتم انشاء

كائن في الدالة الرئيسة main حيث تستخدم هذا الكائن من خلال دالة العضو لعرض رسالة ترحيب على الشاشة. أولا, سوف

نشرح كيفية تعريف صنف يحتوي على دالة عضو واحدة, ثم نشرح كيفية انشاء كائن لهذا الصنف وايضا كيف نقوم بإستدعاء دالة

العضو لكائن لعرض رسالة الترحيب.

الصنف دفتر الدرجات:

يجب قبل بداية دالة الـ main أن نعرف الصنف كما هو موضح في السطور ( 9-17 ) وتسمى هذه

السطور " تعريف الصنف " defining a class.نحن نقوم بتعريف الصنف من أجل المترجم لكي

يتعرف على الصنف ودوال أعضاؤه وأعضاء بياناته.

تعريف دالة العضو displayMessage في السطور ( 13-16 ) بحيث تعرض رسالة ترحيب

على الشاشة كما هو موضح في السطر ( 15 ). إلى السطر 19ويعتبر هذا الصنف عبارة عن ورقة

تصميم ولن يتم تشغيله والإستفادة منه إلى بعد انشاء الكائن في السطر ( 22 ) في الدالة main.

بعدما قمنا بإنشاء كائن نقوم بإستدعاء دالة العضو في الصنف GradeBook من خلال السطر ( 23 ).

تعريف الصنف يبدأ عند السطر ( 9 ) والكلمة المفتاحية لهذا التعريف هي كلمة class متبوعة بإسم

الصنف GradeBook.-عادة ً ما يكون إسم الصنف يبدأ بحرف كبير لكل كلمة فيه وذلك لتسهيل

القراءة. ويسمى هذا الإسلوب في التسمية بالـ camel case السطور ( 10-17 ) هذا الجزء

يسمى جسم الصنف ويبدأ بقوس فتح وينتهي بقوس إغلاق ( {} ) وينتهي بفاصلة

منقوطة ( الفاصلة المنقوطة ضرورية هنا ).

خطأ برمجي شائع

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

تذكر ذلك , أ، الدالة main تستدعى بشكل تلقائي عند كل تنفيذ للبرنامج. هي ليست كمعظم

الدوال كدالة العضو displayMessgae, فهذه الدالة يجب أن تقوم بإستدعائها لتؤدي

عملها كما هو موضح بالسطر 23. يحتوي السطر 11 على محدد وصول من نوع

عام ( public ) وذلك لتحديد نوع الوصول لدالة العضو displayMessage بأن

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

بعض ( : ). فيما بعد سوف نتعلم استخدام محدد وصول من نوع خاص private

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

مهمتها. على سبيل المثال, الدالة التي تقوم بعملية جمع فإنها ترجع قيمة وهي ناتج

الجمع. إذن, عندما تُعرف دالة يجب أن يحدد نوع القيمة المُرَجـَعـَه. في السطر 13, نوع

القيمة المرجعه هو void أي لا شي, بمعنى آخر , أن الدالة لا ترجع شي , فقط تقوم

بطباعة رسالة ترحيب.

المثالية في تسمية الدوال هو ابتداء إسم الدالة بحرف صغير وكل مقطع بعد ذلك يبدأ بحرف

كبير, وذلك كما قمنا به في الدالة displayMessage في طريقة تسميتها. في

السطر 13, تشير الأقواس بعد إسم الدالة أن هذه دالة , أما كون الأقــواس فــيها

فاضية ( ليس بداخلها شي ) فهذا يدل على أن الدالة لا تحتاج إلى بيانات إضافية كي تقوم

بعملها ( سوف ترى دوال تحتاج إلى بيانات إضافية فيما بعد ).

السطر 13 كاملا يسمى ترويسة الدالة ( فاتحة الدالة ) function header ويأتي

بعده جسم الدالة المحدد بأقواس الفتح والإغلاق ( {} ) في السطور ( 14, 16 ).

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

دالة العضو displayMessage تحتوي عبارة واحدة للتنفيذ ( السطر 15 ). ومهمتها

طباعة رسالة ترحيب على الشاشة. بعد تنفيذ هذه العبارة تكون الدالة بذلك قد أنهت مهمتها.

خطأ برمجي شائع

إرجاع قيمة لدالة نوع المُرَجـَع فيها void سوف يولد خطأ ترجمه.

خطأ برمجي شائع

تعريف دالة داخل دالة آخرى.

فحص الصنف GradeBook :

في السطر 22 قمنا بنشاء كائن من نوع GradeBook وأسميناه myGradeBook, لاحظ

أن الكائن عبارة عن نوع قام بتعريفه المستخدم وهو GradeBook على أنه صنف ويحتوي

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

هذا النوع كما في الأسطر ( 9-17 ) فإن المترجم سوف يرسل رسالة خطأ مفادها أنه لم يتعرف

على هذا النوع.

كل صنف جديد أن تقوم بإنشاؤه يعتبر نوع جديد نستطيع أن تستخدمه متى شئت. لهذا لاسبب سميت

هذه اللغة " بلغة قابلة للتمدد ". في السطر 23 نستدعي دالة العضو displayMessage ( معرفة في السطور 13-16 )

بإستخدام المتغير myGradeBook متبوع بنقطه ( . ) ومن ثم إسم الدالة كماهو معين من قبل.

بعد عملية الإستدعاء , التنفيذ سوف يتفرع ليذهب للدالة displayMessage وينفذ

العبارة ( عبارة طباعة رسالة ترحيب على الشاشة ) , وعند انتهاء الدالة يرجع من حيث

تفرع , أي إلى الدالة main, ثم يكمل التنفيذ إلى أن يصل إلى السطر 24 , نهاية الدالة الرئيسة.

تمثيل الصنف GradeBook بالــ UML

الـ UML لغة رسمية مستقلة , يتسخدمها المبرمجون لتمثيل أنظمتهم الكونة من كائنات موجهه

في نمط قياسي. في الـ UML كل عضو كل صنف يكون على شكل انموذج رسم تخطيطي

لمستطيل بثلاثة أجزاء. كما في الشكل التالي:

post-133999-1194173117.jpg

الجزء العلوي يحتوي إسم الصنف, منتصف المستطيل يحتوي على خصائص

الصنف ( أعضاء البيانات في الـC++ ). الجز السفلي من المستطيل يحتوي على

العمليات ( دوال الأعضاء ) وتكون موضوعة على شكل قائمة , في الشكل السابق

وهو ما يمثل صنف الـ GradeBook لدينا هنا دالة عضو واحدة فقط موضوعة

في هذه المستطيل ومسبوقة بإشارة ( + ) , حيث تشير هذه الإشارة إلى نوع الوصول

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

وصف الصنف.

تعريف دالة عضو بوسيط واحد

المثال الثاني

لكي نوضح ماهو الوسيط , سوف نقوم بطرح هذا المثال. لنفرض أن دلينا كائن يمثل حساب بنكي

لأحد العملاء, وأن دالة العضو هي دالة الإيداع deposit من الصنف account. عندما نريد

الإيداع فإننا نحتاج إلى معلومات معينه مثل مقدار الإيداع, فعند عملية مناداة الدالة deposit سوف

نرسل لها قيمة وهي مقدار الإيداع. تنسخ هذه القيمة في متغير في تعريف الدالة ( ترويسة الدالة ),

هذا المتغير يعرف بالوسيط. بعدها تقوم دالة العضو بإضافة هذه المتغير لحساب الرصيد.

تعريف وفحص الصنف GradeBook :

المثال التالي هو تعديل للمثال السابق

 



1  // Fig. 3.3: fig03_03.cpp
2  // Define class GradeBook with a member function that takes a parameter;
3  // Create a GradeBook object and call its displayMessage function.
4  #include <iostream>
5  using std::cout;
6  using std::cin;
7  using std::endl;
8
9  #include <string> // program uses C++ standard string class
10  using std::string;										 
11  using std::getline;										
12
13  // GradeBook class definition
14  class GradeBook
15  {
16  public:
17	 // function that displays a welcome message to the GradeBook user
18	 void displayMessage( string courseName )
19	 {
20		cout << "Welcome to the grade book for\n" << courseName << "!"
21		   << endl;
22	 } // end function displayMessage
23  }; // end class GradeBook
24
25  // function main begins program execution
26  int main()
27  {
28	 string nameOfCourse; // string of characters to store the course name
29	 GradeBook myGradeBook; // create a GradeBook object named myGradeBook
30
31	 // prompt for and input course name
32	 cout << "Please enter the course name:" << endl;
33	 getline( cin, nameOfCourse ); // read a course name with blanks
34	 cout << endl; // output a blank line
35
36	 // call myGradeBook's displayMessage function
37	 // and pass nameOfCourse as an argument
38	 myGradeBook.displayMessage( nameOfCourse );
39	 return 0; // indicate successful termination
40  } // end main

قمنا بإعادة تعريف الصنف GradeBook في السطور ( 14-24 ) كي نستخدم وسيط يحتوي على

اسم الدورة حيث تقوم الدالة displayMessage بعرضه مع رسالة الترحيب. لكي تعرض دالة

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

استخدمنا المتغير courseName كوسيط في السطر 18.

قبل استخدام التقنية الجديدة ( الوسيط ), دعونا نرى طريقة التعامل مع الصنف الجديد في الدالة الرئيسة main.

قمنا بإنشاء متغير جديد من نوع سلسلة string في السطر 28 واسميناه nameOfCourse واستخدمناه

لتخزين اسم الدورة المدخل بواسطة المستخدم. المتغير الجديد يمثل سلسلة من الرموز لأن اسم الدورة عبارة

عن سلسلة من الرموز , مثال : " CS 100 Introduction to C++ programming ". في الواقع

, السلسلة ( string ) هي عبارة عن كائن مكتبة الـ C++ القياسية من صنف السلسلة " string". هذا الصنف

معرف في ملف الترويسة < string> , والإسم string, مثل اسم cout, ينتمي إلى مساحة الأسماء std.

لكي تتم ترجمة السطر 28 يجب أن نضمن السطر 9 في البرنامج. لاحظ أن التصريح في السطر 10 يسمح لنا

بكتابة السطر 28 بدون السابقة :: std.

في السطر 29 أنشأنا الكائن myGradeBook من الصنف GradeBook. وفي السطر 29 نطلب من

المستخدم أن يدخل إسما للدورة من اختيارة. في السطر 33 يقرأ الإسم من المستخدم ويسند للمتغير nameOfCourse

بإستخدام دالة الـ getline من المكتبة القياسية لتؤدي عملية الإدخال.

قبل أن نشرح هذا السطر من الكود ( سطر 33 ) دعونا نوضح لماذا نكتب ( cin >> nameOfCourse; )

بدلا من السطر 33 لنأخذ اسم الدورة من المستخدم. ببساطة , إسم الدورة يتكون من عدة كلمات , بين كل إثنتين

فراغ , فلو استخدمنا هذا السطر لتوقف التخزين عن أول فراغ وإحتوى المتغير nameOfCourse على

المقطع الأول فقط , على سبيل المثال, لو قمنا بتخزين اسم الدورة على هذا الشكل " CS 101 Introduction to C++ programming " فإن

المتغير سوف يحوي المقطع الأول وهو CS 101. أما الدالة getline, فتقوم بتخزين إسم الدورة إلى أول

عملية ضغط على المفتاح enter من لوحة المفاتيح, وبذلك يخزن اسم الدورة كاملا مع الفراغات.

في السطر 33 , الدالة getline(cin< nameOfCours); تقرأ الرموز مع الفراغ من

كائن سيل الإدخال cin حتى أول رمز إدخال. لاحظ ما يلي : " أن المفتاح enter في لوحة المفاتيح

يعتبر رمز. أيضا , أننا عندما نريد أن نستخدم الدالة getline يجب أن ندرج ملف

الترويسة < string > في البرنامج. ايضا تعتبر الـ getline أحد اسماء مساحة الأسماء std.

السطر 38 , نستدعي دالة العضو displayMessage للكائن myGradeBook , في هذا السطر

يسمى " المتغير الممرر " argument, وهو ممرر لدالة العضو displayMessage لكي تستطيع

أن تكمل مهمتها. ففي هذه العملية تؤخذ نسخة من المتغير الممرر nameOfCourse وتوضع في

الوسيط coursName في تعريف الدالة في السطر 18, لاحظ أن اسم الدورة يعرض كجز من رسالة

الترحيب عند تنفيذ البرنامج.

المزيد حول المتغيرات الممررة والوسائط:

عند استخدام المتغيرات الممرة والوسائط , يمكنك ملاحظة مايلي :

1- في السطر 18 ما بين الأقواس, يمكنك وضع أي عدد من الوسائط كلما إحتاجت الدالة لذلك, فما هذه

الوسائط إلا معلومات اضافية تحتاجها الدالة لإكمال مهمتها.

2- في نفس السطر, الدالة لا تتطلب إلا وسيط واحد وهو coursName.

3- كل وسيط يجب أن يحدد نوعة واسمه, الوسيط في هذا الحالة من نوع string " سلسلة رمزية " وامه courseName.

4- في جسم الدالة نقوم بإستخدام هذا الوسيط في عملية الطباعة كما هو موضح في السطر 20 حيث يعرض

الإسم بعد رسالة الترحيب.

5- لاحظ إسم المتغير الوسيط في السطر 18 يمكن أن يكون نفسه أو اسم مختلف عن اسم المتغير الممرر في

السطر 38 ( سوف نتعلم تفاصيل ذلك قريبا ).

6- عدد وترتيب الوسائط فيترويسة الدالة ( سطر 18 ) يجب أن يكون مربوط بعدد وترتيب المتغيرات الممرره في استدعاء

الدالة ( سطر 38 ) , كذلك النوع نفس الحالة.

خطأ برمجي شائع :

وضع فاصلة منقوطة بعد القوس الايمن بعد قائمة الوسائط في تعريف الدالة سوف يولد خطأ نصي.

خطأ برمجي شائع :

تعريف وسائط الدالة مرة اخرى كمتغيرات محلية في الدالة يولد خطأ في الترجمة.

لممارسة برمجية جيدة:

لتجنب الغمووض , تجنب استخدام نفس الأسماء لأسماء المتغيرات الممرره للدالة والوسائط المقابلة في تعريف الدالة.

لممارسة برمجية جيدة:

إستخدام أسماء للدوال ذات معنى وأيضا , اسماء الوسائط, يجعل البرنامج سهل القراءة ويساعد على تجنب الإفراط في وضع التعليقات.

تحديث الـ UML بعد التعديل للصنف GradeBook:

الشكل التالي يمثل الـ UML بعد تعديل البرنامج :

post-133999-1194173123.jpg

التغيير فقط في المستطيل السفلي, حيث قمنا بإضافة وسيط اسمه coursName ونوعة string

والنقطتان ( : ) وضعت للفاصل بين الوسيط ونوعة.

لاحظ أن الصنف GradeBook لا يحتوي حتى الآن أي من أعضاء البيانات ( المستطيل في الوسط ).

أنتهت المحاضرة

بسبب ترابط مواضيع هذا الفصل , لا يوجد اسئلة تمارين لهذا الفصل حتى ننتهي منه في المحاضرة القادمة

وسوف تكون المحاضرة القادمة يوم السبت , والمحاضرة التي تليها يوم الجمعة , لترجع مواعيد المحاضرات إلى طبيعتها بعد ذلك

post-133999-1194173117_thumb.jpg

post-133999-1194173123_thumb.jpg

post-133999-1194173226_thumb.jpg

post-133999-1194173234_thumb.jpg

تم تعديل هذه المشاركة بواسطة BjarneStudent في 4 نوفمبر 2007 في 13:56

1

وليس يبني العلا الا نديٌ ووغى , همـا المعارج للأسنى من الرتب

#2

بارك الله فيك

وان شاء الله نكون عند حسن ظن الجميع بإذن الله

تابع فكلنا لك آذان صاغيه

#3

أحسنت . عرض واضح ومفهوم.

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

tvquran_6.gif

#4
hasan.cpp كتب:
بارك الله فيك

وان شاء الله نكون عند حسن ظن الجميع بإذن الله

تابع فكلنا لك آذان صاغيه

جزاك الله خير

اشكرك

arabi2013 كتب:
أحسنت . عرض واضح ومفهوم.

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

شاكر متابعتك ودعاؤك

جزيل الشكر

وليس يبني العلا الا نديٌ ووغى , همـا المعارج للأسنى من الرتب

#5

شكرا على الشرح وإن شاء الله تكون دروسك في ميزان حسناتك و لكن حبذ لو قمت بالشرح أيضا على السي

''‏اللهم إني أسالك إيمانا دائما وأسألك قلبا خاشعا وأسألك علما ‏نافعا وأسألك يقينا صادقا وأسألك دينا قيما وأسألك العافية من كل ‏بلية''

'‏اللهم أغفر للمؤمنين و المؤمنات و المسلمين و المسلمات الأحياء ‏منهم و الأموات'

www.it-scoop.com

#6

السلام عليكم ..

شكراً جزيلاً على هذه السلسة القيمة من الدروس في لغتننا المحبوبة ++C ,,

أردت فقط إضافة التالي :

كثيراُ ما يتم الخلط بين مفهوم الفئة Class و الكائن Object, و هذا راجع إلى صعوبة استعياب مفهوم البرمجة الكائنية OOP في الأصل - هذه حقيقة فالبرمجة الكائنية ليست بتلك السهولة -, إن أفضل طريقة حقيقة لفهم الموضوع هو تخيله على الشكل التالي :

لو أخذنا مثالك حول فئة Class السيارة - على سبيل المثال - فإنا نتكلم عن مفهوم و ليس عن شيء حقيقي موجود فعلاً.. فلو قلت لك أن هذه سيارة سوف يخطر في بالك أن لها عجلات و مقود .... إلخ

و لكن هل يمكن أن تتطابق سيارتان مع بعضهما البعض ؟

الحقيقة , لا و لكن يمكن أن يتشابها في بعض الأمور مع ضرورة وجود اختلاف بينهما في بعض الصفات - لو كان هناك شيئان متطابقان تماماُ فنحن نتكلم عن نفس الشيء و ليس عن شيئين مختلفين - .

أنا متأكد أنك لم تفهم ماذا أردت بهذا الكلام .. لماذا إذأً قمت بذكر المثال الذي في الأعلى ؟

لأننا عندما ننظر إلى أي أي سيارة فهي كائن قائم بذاته و لكننا نعرف أيضاُ أن جميع السيارات التي ننظر إليها ما هي إلا عبارة عن تطبيق لفكرة مجردة و هي السيارة !

فسيارتي على سبيل المثال هي كائن ,, و لن أخطئ أبداُ و أقول أنها دراجة لأننا نعرف ما هي السيارة ..

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

#7
SIFE-C كتب:
شكرا على الشرح وإن شاء الله تكون دروسك في ميزان حسناتك و لكن حبذ لو قمت بالشرح أيضا على السي

العفو اخي الكريم

بالنسبة للشرح بلغة السي , هل من ضرورة لذلك ؟

Khaled.Alshaya كتب:
السلام عليكم ..

شكراً جزيلاً على هذه السلسة القيمة من الدروس في لغتننا المحبوبة ++C ,,

أردت فقط إضافة التالي :

كثيراُ ما يتم الخلط بين مفهوم الفئة Class و الكائن Object, و هذا راجع إلى صعوبة استعياب مفهوم البرمجة الكائنية OOP في الأصل - هذه حقيقة فالبرمجة الكائنية ليست بتلك السهولة -, إن أفضل طريقة حقيقة لفهم الموضوع هو تخيله على الشكل التالي :

لو أخذنا مثالك حول فئة Class السيارة - على سبيل المثال - فإنا نتكلم عن مفهوم و ليس عن شيء حقيقي موجود فعلاً.. فلو قلت لك أن هذه سيارة سوف يخطر في بالك أن لها عجلات و مقود .... إلخ

و لكن هل يمكن أن تتطابق سيارتان مع بعضهما البعض ؟

الحقيقة , لا و لكن يمكن أن يتشابها في بعض الأمور مع ضرورة وجود اختلاف بينهما في بعض الصفات - لو كان هناك شيئان متطابقان تماماُ فنحن نتكلم عن نفس الشيء و ليس عن شيئين مختلفين - .

أنا متأكد أنك لم تفهم ماذا أردت بهذا الكلام .. لماذا إذأً قمت بذكر المثال الذي في الأعلى ؟

لأننا عندما ننظر إلى أي أي سيارة فهي كائن قائم بذاته و لكننا نعرف أيضاُ أن جميع السيارات التي ننظر إليها ما هي إلا عبارة عن تطبيق لفكرة مجردة و هي السيارة !

فسيارتي على سبيل المثال هي كائن ,, و لن أخطئ أبداُ و أقول أنها دراجة لأننا نعرف ما هي السيارة ..

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

الشكر الجزيل لإضافتك

وهذا ما اشرنا إليه في المحاضرة الأولى , تحت الموضوع " مصطلحات ومفاهيم الكائنات الأساسية " .. في نهاية المحاضرة .. لمن اراد الإطلاع من هنا

وليس يبني العلا الا نديٌ ووغى , همـا المعارج للأسنى من الرتب

#8

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

أشكرك على المحاضرة . الحمد لله قد إستطعت فهم الكثير منها.

لكن أرجو أن توضح لي أكثر . ما الفرق بين المتغير . والوسيط .

وجزاك الله كل خير وجعل هذا العمل في ميزان حسناتك يوم القيامة .

eteba3.png

(قل إن كنتم تحبون الله فاتبعوني يحببكم الله)

#9
اقتباس
السلام عليكم ورحمة الله وبركاته

أشكرك على المحاضرة . الحمد لله قد إستطعت فهم الكثير منها.

لكن أرجو أن توضح لي أكثر . ما الفرق بين المتغير . والوسيط .

وجزاك الله كل خير وجعل هذا العمل في ميزان حسناتك يوم القيامة .

سؤال جيد ,,

سأذكر ما هما ثم سأذكر طريقة الاستخدام ,, ثم سأذكر تفاصيل تقنية لن تحتاجها في الغالب عند عملية البرمجة بشكل عام ,,

نحن نعرف أن كل متغير في ++C يتم تعريفه في مجال معين كخواص الفئات ( متغيراتها ) أو في دوال ... المهم أنها تكون معرفة في مجال لا يمكن الوصول إليها من خارجه ,,

أو الحالة الثانية و هي أن يكون المتغير global و بالتالي يمكن الوصول إليه من أي مكان من البرنامج ,,

من صمم طريقة عمل الدوال في ++C أرد أن تكون مدخلات الدالة خاصة فيها أو ما يسمى private variables ,, وبالطبع هكذا تكون الدالة قائمة بذاتها و لا نحتاج على سبيل المثال للاتفاق على متغير عام كمدخل للدالة ,, و بالتالي تصبح الدالة متنقلة لأبعد الحدود و قائمة بذاتها كما قلنا سابقاً ,,

لذلك تم الاتفاق على الشكل الذي تبدو عليه الدوال حالياً ,, و ذلك يقضي بان يتم تمرير المتغيرات المدخلة للدالة و تسميتها وسيطة و جمعها وسائط :D بين قوسين بعد استدعاء اسم الدالة ,,

عرفنا ما هي المتغيرات و الوسائط بشكل عام و لنأخذ مثالاُ عليها في ++C

مثال على الوسائط فقط ( المفروض أنك تعرف ما هي المتغيرات ;) ) :

// Writing the function
int func ( int x ){	// ( int x ) x here is a "parameter" '1'
	x = x*x;	// x = x^2
	return x;
}
// calling func()
int x = 3;	// x here is a variable defined in the main for example. '2'
int y = 0;	// The result of 'func' will be in y.

y = func( x );	// x here is an argument!!!. '3'
		// after calling the function x = 3, y = 9

في المرة الأولى عرفنا x على انه وسيط للدالة و المرة الثانية عند استدعاء الدالة قمنا بتمرير المتغير x الثاني و قمنا بتمريره للدالة ,, هذه هي الحكاية ,,

أي أن ما يصل للدالة هو نسخة عن المتغير الأصلي و ليس المتغير الأصلي نفسه ,,

================================================================================

========

و لو أنك كنت شديد الملاحظة و قرأت الكود ,, فستجد أنني كتبت في الملاحظات عند كتابة الدالة "مكان تعريفها" أن x هو وسيط parameter و في المرة الثانية عند استدعائها كتبت أنها وسيط argument و معنى الكلمتين متطابق فما هو الاختلاف ,,

هنا سأدخل في بعض التفاصيل التقنية فلا تدخل بدون كأس من الشاي :evil:

لو كان لديك القليل من الخبرة البرمجية و الاطلاع على لغة الاسمبلي ,, فستفهم الفكرة بشكل كامل لأن المترجم يقوم بترجمة برنامجك إلى لغة الاسمبلي ( لغة الاسمبلي و الالة متطابقتان ) و يصبح كودك بعدها في عداد الأموات ,,

المهم أن الحل الذي ذكرته في الأعلى ,, و ذلك بأن تكون مدخلات الدالة متغيرات private أوجد مشكلة عويصة حقاً :hmm:

المشكلة ليست بتلك الصعوبة بل بسبب وضوحها الشديد لم نراها :thumbup:

افترض أن لديك مصفوفة مكونة من 10000 الاف عنصر و تريد من دالة معينة أن تجري عملية معينة على هذه المصفوفة - 10000 عنصر عدد قليل جداً و عادي لو ذكرنا قواعد البيانات في الموضوع - فهل يجب أن يتم نسخ كامل للمصفوفة للدالة ثم اجراء العمل المطلوب عليها ثم اعادة المصفوفة مرة أخرى ,,

الجواب المنطقي هو : لا ,,

إذا ما هو الحل ؟

الحل يكمن في أن تبقى الوسائط متغيرات خاصة بالدالة ,, و لكن مع اضافة امكانية تمرير "المتغيرات variables" أو "عناوين المتغيرات addresses of variables"

طبعاُ عند سماع اسم "عنوان" لدى المبرمجين سيخطر في البال على الفور موضوع المؤشرات pointers و هذا طبيعي لأنها الأداة التي توفرها ++C للتعامل مع العناوين ,,

و لكن ما علاقة العناوين في موضوعنا ,, و بالمناسبة اللغة الوحيدة التي أعرفها التي توفر تعامل كامل مع العناوين كما توفره مع المتغيرات ,,

طبعاً لو أخذنا المثال السابق و أضفنا & قبل اسم المتغير فسيتم تمرير العنوان و ليس قيمة المتغير ,, كما في المثال التالي ,,

// Writing the function
int func ( int &x ){	// ( int x ) x here is a "parameter" "reference parameter"; '1'
	x = x*x;	// x = x^2
	return x;
}
// calling func()
int x = 3;	// x here is a variable defined in the main for example. '2'
int y = 0;	// The result of 'func' will be in y.

y = func( x );	// x here is an argument!!!. '3'
		// after calling the function x = 9, y = 9

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

أما في الحالة الأولى فلم تتغير قيمة x حتى بعد اجراء العمليات عليها لأننا حصلنا على نسخة من قيمة المتغير و مررناها للدالة ,,

أعتقد أني أطلت كثيراً في الشرح ,, و إذا أردت تفاصيل تقنية أكثر عن الفرق حتى على مستوى لغة الاسمبلي فانا في الخدمة بعد الإجابة على أسئلتك ,,

تحياتي ,,

تم تعديل هذه المشاركة بواسطة Khaled.Alshaya في 3 ديسمبر 2007 في 07:22

#10

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

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

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

والأن إليك التالي :

اقتباس
و بالتالي تصبح الدالة متنقلة لأبعد الحدود و قائمة بذاتها

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

*(( المتغيرات المدخلة للدالة تمرر وتسمي وسائط .))

س2 / هل هذا التعريف صحيح ؟ وإن كان صحيح . فأرجو أيضا التوضيح أكثر إلي أين تمرر .

ولا تقلق عزيزي فلا زال هناك شاي با الكأس :D

طلب أخر . أطلبه على إستحياء .

(( أنا مبتدا بعالم البرمجة . مبتدا جداً . وأرغب في التعالم . لذلك حضرتكم ستروا

أن الأسئلة بدائية . واحياناً ربما تكون مستفزة . لذلك أرجو الأ تملوا مني :unsure: ))

شكر جزيلاً ودمتم في رعاية الله ...

eteba3.png

(قل إن كنتم تحبون الله فاتبعوني يحببكم الله)

#11

السلام عليكم ,,

لا داعي للشكر أخ HUNTER الشكر لله الذي يسر لنا معرفة هذه الأمور ,,

ندخل على الأسئلة ,, :wink:

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

ما كنت أقصده بـ "متنقلة لأبعد الحدود" هو أنه يمكن استدعاء الدالة دون وجود عملية فيها تعمتد على شيء خارجها :hmm:

أعتقد أن المثال سيوضح كل شيء,,

تصور أنه لا يوجد شيء اسمه وسائط , و أنك تريد تمرير قيمة ما للدالة لحساب مربع عدد,, الطريقة الوحيدة هي الاتفاق بين مبرمج الدالة و الذي يقوم ببرمجة الدالة الرئيسية main على استخدام متغير global مثال على ذلك ,,

#include <iostream>
using namespace std;

int func(){
	int y = x*x;
	return y;
}
int x;
int main(){

	cin >> x;
	int z = func();
	cout << z;
	return 0;
}

انظر الى الكود جيداُ ,, هل يمكن أن تعمل الدالة func بدون المتغير العام x ,,

الجواب هو لا,, هذا ما كنت أقصده ,, أي أنه يجب الاتفاق بين المبرمجين على اشياء المفروض أن يخفوها عن بعضهم البعض :angry:

طبعاُ أعتقد أنك قرأت الدورس الأولى حول "الكبسلة" أو التغليف ,,

و هذا هو تطبيق النظرية في الدوال ,,

و لنجعل الوضع أسوأ تصور أن الدالة تستدعي نفسها بما يسمى الـ recursion

صراحة لا أستطيع تخيل ما الذي سيحدث ؟؟؟؟

اقتباس
*(( المتغيرات المدخلة للدالة تمرر وتسمي وسائط .))

س2 / هل هذا التعريف صحيح ؟ وإن كان صحيح . فأرجو أيضا التوضيح أكثر إلي أين تمرر .

نعم هذا التعريف صحيح,, و لكن يجب تحديد ما معنى كلمة "تمرير"

كمبرمج ++C كل ما تحتاج لمعرفته هو أن الوسائط إما أن تمرر قيمتها أو أن يمرر عنوانها ,,

في الحالة الأولى بدون & و في الحالة الثانية مع &

في الحالة الأولى لا يتم تغيير المتغير الأصلي بل يبقى على حاله لأننا أرسلنا نسخة من قيمته للدالة بطريقة ليس من المهم معرفتها !

و في الحالة الثانية أرسلنا لها عنوان المتغير و بالتالي إذا عرفت عنوان المتغير أصبح بإمكان الدالة الوصول للمتغير الأصلي و تغييره,

أما لو أردنا الدخول في بعض التفاصيل عن عملية التمرير نفسها ,, فيجب قبل ذلك ان نكون على اطلاع بالـ Stack و هي من أبسط الـ Data Structures و كيف يتم استدعاء الدوال,, و ما هو العنوان و كم يحجز مساحة من الذاكرة في بيئة 32 - 16 بت على سبيل المثال ,, وكل هذه الأمور لا تهم من يبرمج بلغة عالية المستوى حتى و لو كانت ++C,,

أنصحك بالإكتفاء حالياُ لحين تعلم الـ pointers و معرفة عمل الذاكرة قليلاً ,, قبل الاقدام على دراسة مثل هذه الأمور,,

تحياتي ,, و أنا جاهز للأسئلة القادمة :thumb_up:

#12

السلام عليكم

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

وأكيد أكيد سيكون هناك أسئلة أخر .

eteba3.png

(قل إن كنتم تحبون الله فاتبعوني يحببكم الله)

#13
HUNTER OF THE DREAMS كتب:

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

أشكرك على المحاضرة . الحمد لله قد إستطعت فهم الكثير منها.

لكن أرجو أن توضح لي أكثر . ما الفرق بين المتغير . والوسيط .

وجزاك الله كل خير وجعل هذا العمل في ميزان حسناتك يوم القيامة .

العفو أخي صياد الأحلام

بالنسبة للسؤال , ماقصر الأخ خالد الشايع , شرح رائع ومستفيض

ولكن هذا لا يمنع أن اطرح هذا المثال لتوضيح الفرق , وذلك من باب الإضافة والزيادة في الإستيعاب

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

إلى السيارة , وبعدها سوف تستغني عنها

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

هي تقنية لغرض الترتيب والتنظيم والهندمه

واذا كان لديك أي سؤال , يمكنك طرحة في نفس موضوعه , على الرحب والسعة

وليس يبني العلا الا نديٌ ووغى , همـا المعارج للأسنى من الرتب

#14

مشكور وبارك الله فيك وزادك من العلم

تقبل مروري

#15

درس جميل جدا ورائع

والحمد لله تم التطبيق بنجاح

ولكن فى البداية وجدت عنى اخطاء فى حالة الاحرف الصراحة دوخت لحد ما احظت الاخطاء رجعت كتبت الكود من الصفر حتى استطيع ان احل المشكلة :(

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

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