مجلس أوراق ملونة أوراقـ متساقطهـ على شغافـ قلوبكمـ .. [تم تحديث قوانين القسم نسعد بإطلاعكم]


عدد مرات النقر : 25,694
عدد  مرات الظهور : 36,509,938

موضوع مغلق
 
LinkBack أدوات الموضوع انواع عرض الموضوع
قديم 21-10-2005, 07:40 AM   #1

الصورة الرمزية عبد الله الساهر

 رقم العضوية :  1
 تاريخ التسجيل :  22-07-2004
 المشاركات :  70,777
 الدولة :  ムレ3乃乇乇尺
 الجـنـس :  ذكر
 العمر :  38
 عدد النقاط :  243859
 قوة التقييم :  عبد الله الساهر تم تعطيل التقييم
 SMS :

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

 اخر مواضيع » عبد الله الساهر
 تفاصيل مشاركات » عبد الله الساهر
 أوسمة و جوائز » عبد الله الساهر
 معلومات الاتصال بـ عبد الله الساهر

افتراضي التراكيب في لغـة ++c


بسم الله الرحمن الرحيم
الدرس الأول
التراكيب في لغـة السي بلس بلس
Structured In C++ Languge

هذا هـو أول درس جدي في هذه السلسلة كل ما أطلبه منك هـو التركيز جيداً ، وتذكر أن هذه المادة لا ينفع معها القراءة السريعـة بل القراءة المتأنية....
الكائن عبارة عـن رزمـة ، قد تتساءل ما هي مكونات هذه الرزمـة ، هذه الرزمـة مكونـة من دوال ومتغيرات تندرج تحت هذا الكائن...
تحاول البرمجـة الكائنية تقليد الواقع العـملي لذلك عليك التفكير بها من هذه الناحيـة، كما تعلم فإن كل شيء في هذه الحياة عبارة عـن كائن ، مثل الإنسان أو الحيوان أو أي شيء آخر ، من هذا المنطلق لنأخذ مثلاً من الحياة العـملية ، وهـو كائن الطالب ، كائن الطالب عبارة أولاً عـن إنسان وبالتالي فهـو يحوي جميع خصائص الإنسان ، لننظر إلى كائن الطالب من ناحية برمجية كائنية ، لن نقول أولاً أن كائن الطالب عبارة عـن إنسان ، لأننا أولاً لن نستطيع كتابة جميع ما يقوم به الإنسان في برنامج بل سنهتم بالناحية التي تهـمنا كمبرمجين أو إلى احتياجات البرنامج الذي نقوم بكتابته ، سننظر إلى كائن الطالب أنه عبارة عـن مجموعـة من المواد وكل مادة مكونـة من درجـة وأنه مكوّن أيضاً من اسمه الرباعي ورقمـه التسلسلي .... أنظر إلى كيف سنكتب صنف الطالب في لغـة السي:

كود:
CODE1. struct student {
2. char itsName[200];
3. int itsNumber;
4. float gradesOfCourses[5];
5. int itsAvg;
6. };
حسناً لنقل أنك تقوم بكتابة برنامج يقوم بحساب مجموع درجات الطالب ، ويوجد معـدل الطالب من 4 ، أنظر إلى هذا البرنامج بشكل كامل، وسننتقل الآن إلى البرمجـة بلغـة السي بلس بلس وليس السي:

كود:
CODE1. #include <iostream>
2. using namespace std;
3. 
4. struct student {
5. char itsName[200];
6. int itsNumber;
7. float gradesOfCourses[5];
8. float itsAvg;
9. }
10.;
11. int main()
12. {
13.  student Ahmed;
14.  for(int i = 0;i < 5;i++) {
15.   cout << "Enter the grade of course" << i+1 << ":\t";
16.   cin >> Ahmed.gradesOfCourses[i];
17.  }
18.  int total=0;
19.  for( i=0; i< 5;i++)
20.   total+=Ahmed.gradesOfCourses[i];
21. 
22.  int avg=total/ 5;
23. 
24.  Ahmed.itsAvg = (avg*4) /100;
25.  cout << Ahmed.itsAvg << endl;
26. 
27.  return 0;
28. }
لن أشرح لك هذا الكـود فهـو بسيط ، ولكن لنفرض أنك قررت زيادة عـدد مواد الطالب إلى 10 ، وليس ذلك فحسب بل قررت أيضاً حساب المعـدل بالنسبة المئويـة:

كود:
CODE1. #include <iostream>
2. using namespace std;
3. 
4. struct student {
5. char itsName[200];
6. int itsNumber;
7. float gradesOfCourses[10];  /*  يوجد تغيير في حجم المصفوفة  */
8. float itsAvg;
9. }
10.;
11. int main()
12. {
13.  student Ahmed;
14.  for(int i = 0;i < 10;i++) { /*  يوجد تغيير في شرط الحلقة  */
15.   cout << "Enter the grade of course" << i+1 << ":\t";
16.   cin >> Ahmed.gradesOfCourses[i];
17.  }
18.  int total=0;
19.  for( i=0; i< 10;i++)    /* يوجد تغيير في شرط الحلقة  */
20.   total+=Ahmed.gradesOfCourses[i];
21. 
22.  float avg=total/ 10; /*  يوجد تغيير في المقسوم عليه  */
23. 
24.  Ahmed.itsAvg = avg;   /*  يوجـد تغيير كامل في طريقة حساب المعـدل  */
25.  cout << Ahmed.itsAvg << endl;
26. 
27.  return 0;
28. }
قد ترى التعـديلات التي قمت بها بسيطـة ولكن بعـد بسيط فإن التعـديلات التي قمت بها هي خمس تعـديلات ؛ قد ترى الأمر بسيطاً للغاية ، ولكن ماذا لو كان الأمر أكثر من ذلك بكثير ؛ ماذا لو طلب منك مثلاً جعل حجم مواد الطلاب ديناميكي وليس ثابت ، أيضاً لقد قمت بخمس تعـديلات على تركيب struct لا يتجاوز حجم أسطره عـن خمسة أسطر ؛ ماذا لو كان أكبر من ذلك بكثير ... إذا ما هـو الحل برأيك؟ ؛ الحل الذي تريده أنت الآن هـو أن تجعل التركيب student ، يقوم بتعـديل المعـدل أو المتغير itsAvg ، حسب الطلب ؛ وليس أن تقوم أنت بتغيير المعـدل كلما أردت فعل ذلك...
الحل المثالي الذي ستقوم بـه ؛ هـو إضافة دالة عضو جـديدة تقوم بحساب المعـدل من أي رقم تريده من 100 أو من 1000 أو من 5 أو من أي رقم آخر ؛ قد تستغرب إضافة دالة إلى تركيب لتصبح عضواً فيه مثل أي عضو متغير ، في السي بلس بلس هذا الأمر مسموح ، لكن في لغـة السي غير مسموح ، أنظر الآن إلى التعـديلات التي أجرينها على التركيب student :
كود:
CODE
1. struct student {
2. char itsName[200];
3. int itsNumber;
4. float gradesOfCourses[10];
5. float itsAvg;
6. void CalculatorOfAvg(int = 100);
7. };
8. 
9. void student::CalculatorOfAvg(int m)
10. {
11.  for(int i = 0;i < 10;i++) {
12.   cout << "Enter the grade of course" << i+1 << ":\t";
13.   cin >> gradesOfCourses[i];
14.  }
15.  float total=0;
16.  for( i=0; i< 10;i++)
17.   total+=gradesOfCourses[i];
18. 
19.  int avg=total/ 10;
20. 
21.  itsAvg = (avg*m) /100;
22. }
أنظر إلى السطر السادس ألا تجـد أني قمت بإضافة دالة اسمها CalculatorOfAvg ، هذه الدالة تقوم بحساب المعـدل الجامعـي بناءً على البارامتر الممرر إليها ؛ إذا لم يمرر المستخدم إليها شيئاً فستقوم افتراضياً بحساب المعـدل الجامعي من 100 .
الآن أنظر إلى الدالة main والتي سنستخدمها لحساب المعـدل مثلاً من 10 ؛ أنظر ولاحظ الفرق بينها وبين الأكواد السابقة:

كود:
CODE1. int main()
2. {
3.  student Ahmed;
4.  Ahmed.CalculatorOfAvg(4);
5.  cout << Ahmed.itsAvg << endl;
6.  return 0;
7. }
قد تقول مثلاً أن الأسطر التي كانت موجودة في الدالة main والتي تقوم بحساب المعـدل الجامعي قد قمت بإضافتها إلى التركيب struct في الدالة CalculatorOfAvg ، وأن كل ما قمت به هـو أنك رفعت أسطر من مكان ووضعتها في مكان آخر ...
حسناً كل ما تقوله صحيح ، ولكن الفرق بين الطريقة التقليدية وهذه الطريقة الجـديدة ، هـي أني أرحت نفسي من عـناء التفكير في أمور المعالجـة وكيفية حساب المعـدل الجامعي ، أيضاً أرحت من سيأتي من بعـدي ممن يريد استخدام التركيب الذي صنعتـه من قراءته كله ؛ فيكفيه أن يرى الدالة CalculatorOfAvg حتى يعرف ما تقوم به وبالتالي يريح نفسه من عـناء التفكير في قضية حساب المعـدل الجامعـي ...
الخلاصـة:
لقد انتهى الدرس الأول .. وأتمنى منك إعادة قراءتـه فهـو مهـم لمن لا يعرف الفائدة القصوى التي تقدمها البرمجـة الكائنية ، والفرق بينها وبين البرمجـة الإجرائية أو الهيكلية ، لقد تعلمت الفرق بين الـ struct في لغـة السي والـ struct في لغـة السي بلس بلس ، وتعلمت أيضاً ولو بتلميح بسيط للغاية كيف تقوم بالفصل بين المعالجـة والواجهـة وكيف اختصرت الكثير من الجهـد حينما أضفت الدالة CalculatorOfAvg .

توقيع :





رحمك الله يا أنس
وجعل الفردوس دارك ومستقرك



عبد الله الساهر غير متواجد حالياً
رسالة لكل زوار منتديات العبير

عزيزي الزائر أتمنى انك استفدت من الموضوع و لكن من اجل منتدى ارقي و ارقي برجاء عدم نقل الموضوع و يمكنك التسجيل معنا و المشاركة معنا و النقاش في كافه المواضيع الجاده اذا رغبت في ذلك فانا لا ادعوك للتسجيل بل ادعوك للإبداع معنا . للتسجيل اضغظ هنا .

قديم 21-10-2005, 07:41 AM   #2

الصورة الرمزية عبد الله الساهر

 رقم العضوية :  1
 تاريخ التسجيل :  22-07-2004
 المشاركات :  70,777
 الدولة :  ムレ3乃乇乇尺
 الجـنـس :  ذكر
 العمر :  38
 عدد النقاط :  243859
 قوة التقييم :  عبد الله الساهر تم تعطيل التقييم
 SMS :

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

 اخر مواضيع » عبد الله الساهر
 تفاصيل مشاركات » عبد الله الساهر
 أوسمة و جوائز » عبد الله الساهر
 معلومات الاتصال بـ عبد الله الساهر

افتراضي


ملحوظة بسيطة :-

تستطيع تغيير كلمة struct إلى class كلاهما تأديان نفس الغرض في لغة ++C

struct في لغة السي وتستطيع أن تعمل بها في ++C

class في لغة ++C ولا تستطيع أن تعمل بها في C

عبد الله الساهر غير متواجد حالياً
قديم 21-10-2005, 07:48 AM   #3

الصورة الرمزية عبد الله الساهر

 رقم العضوية :  1
 تاريخ التسجيل :  22-07-2004
 المشاركات :  70,777
 الدولة :  ムレ3乃乇乇尺
 الجـنـس :  ذكر
 العمر :  38
 عدد النقاط :  243859
 قوة التقييم :  عبد الله الساهر تم تعطيل التقييم
 SMS :

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

 اخر مواضيع » عبد الله الساهر
 تفاصيل مشاركات » عبد الله الساهر
 أوسمة و جوائز » عبد الله الساهر
 معلومات الاتصال بـ عبد الله الساهر

افتراضي


الدرس الثاني
التراكيب في لغـة السي بلس بلس (2)
Structured In C++

ما زلنا بعـد في موضوع التراكيب ؛ الذي أريده الآن منك أن تعرف الفرق بين التركيب والمتغير من نفس نمط التركيب وهـناك مواضيع كثيرة يجب عليك فهـمها....

الفرق بين التراكيب والمتغيرات:

أنظر الآن إلى تركيب الطالب الذي قمنا بكتابتـه في الدرس الأول:

كود:
CODE1. struct student {
2. char itsName[200];
3. int itsNumber;
4. float gradesOfCourses[10];
5. float itsAvg;
6. void CalculatorOfAvg (int = 100);
7. };
الآن أنظر إلى هذا السطر:
كود:
CODEstudent Ahmed;
هل تعرف الآن ما هـو الفرق بين الكودين .
هل قام الكود الأول بأي حجز للذاكرة ، هل سيقوم المترجم في الكـود الأول بإنشاء صنف أو تركيب اسمـه student وحجز ذاكرة له.... الجواب هـو لأ ؛ لن يكون هـناك أي حجز للذاكرة في الكـود الأول ، كل ما ستقوم بـه هـو إعلام المترجم بأن هـناك صنف أو تركيب جـديد هـو student .... وبالتالي فحينما تقوم بكتابة الكود الثاني فلن يقوم المترجم بإصدار أي خطأ ، الكود الثاني يقوم بحجز للذاكرة ، حيث يقوم بإنشاء متغير أو كائن (سمه ما شئت ) تحت اسم Ahmed ويحجز له الذاكرة التي تشغلها النـوع أو النمط أو الصنف (سمـه ما شئت ) وهـو student .

* دالة البناء:تعلمت في الفقرة السابقـة ما هـو الفرق بين البنيـة struct والمتغيرات المعرفة من نفس نمطها ، وتعرفت في الفقرة السابقـة على بنيـة أو صنف الطالب ؛ ما رأيك الآن أن نقوم بتطوير صنف الطالب ليصبح أكثر فاعلية ؛ هل تتذكر كيف أضفنا الدالة CalculatorOfAvg ، وكيف أراحتنا من عـناء الكتابة في الدالة main ؛ ما رأيك الآن أن نجعل البنية student تستطيع من خلالها تغيير عدد مواد الطالب ؛ تستطيع ذلك إذا نظرنا للأمر من ناحية إجرائيـة ولكن دعـنا ننظر إلى الأمر من ناحية كائنية ، البنية student يجب أن تكون مستقلة عـن التغييرات الخارجيـة ، لنفترض أن أحد المبرمجين طلب منك كتابة بنيـة أو تركيب اسمها student ، وطلب منك أن لا يكون لها مثيل ، عليك الآن أن تجعل التركيب مريحاً للغاية للمبرمج الذي طلب منك إنشاءه ؛ فمثلاً لو أردنا تغيير عـدد المواد ، الآن إما أن تقوم بهذه المهـمـة بنفسك أو تجعلها للمبرمج الآخر ؛ من الأفضل أن تقوم بها بنفسك فمن الممكن أن يكون المبرمج الآخر هـو رئيسك في العـمل ؛ دعـنا الآن نرجع إلى مهـمـة تغيير عـدد المواد ، أي المطلوب منك الآن أن تجعل المصفوفة العضو في التركيب student مصفوفة ديناميكيـة ، ومن الأفضل أن تقوم بكتابة متغير جـديد هـو عـدد المواد ، أنظر إلى النسخـة الثانية من التركيب student :
CODE
كود:
1. struct student {
2. char itsName[200];
3. int itsNumber;
4. float* gradesOfCourses; /* هذا هـو التغيير الأول حيث سنقوم بالتحويل إلى مصفوفة ديناميكة */
5. float itsAvg;
6. void CalculatorOfAvg (int = 100);
7. int NumberOfCourses;   /*  هذا هـو التغيير الثاني حيث وضعـنا متغير لعـدد المواد  */
8. };
هـناك تغييرين فقط ، الآن دعـنا نقرر هل نترك مهـمـة تعيين أو حجز الذاكرة للمصفوفة الديناميكية gradesOfCourses للمبرمج الذي طلب منا القيام ببرمجـة هذا التركيب أو نحن من سنقوم به ؛ من الأفضل أن نقوم به نحن ؛ فالبرمجـة الكائنية تقول لك دائماً إذا قمت بكتابة أي كائن أو تركيب فلا تتركـه حتى يكون كاملاً ومستقلاً وحتى يصبح لا يحتاج للتغيير من المبرمجين الآخرين ؛ ماذا سنفعل الآن وكيف سنحجز الذاكرة للمؤشر gradesOfCourses ؛ إليك الجواب سنقوم بكتابة دالة بناء ؛ ما هي دالة البناء ؟ ؛ دالة البناء هي التي تقوم ببناء التركيب أو الكائن وتحجز له الذاكرة ، كيف نكتب دالة البناء ، دالة البناء تحمل نفس اسم التركيب الذي ستقوم ببناءه ، وهي لا تعيد أية قيمـة وبإمكانها استقبال وسائط أو بارامترات ، دعـنا الآن نقرر كيف سنقوم بكتابة دالة البناء ، على دالة البناء أن تقوم بتهيئـة المتغير NumberOfCourses بعـدد المواد المطلوبة ، وعليها أيضاً أن تحجز الذاكرة للمؤشر gradesOfCourses ، أنظر الآن إلى تركيب student بحلته الجـديدة:

كود:
CODE1. struct student {
2. student (int )  /*   هذه هي دالة البناء  */
3. char itsName[200];
4. int itsNumber;
5. float* gradesOfCourses; 
6. float itsAvg;
7. void CalculatorOfAvg (int = 100);
8. int NumberOfCourses;   
9. };

ليس هـناك إلا تغيير وحيد فحسب ، وهـو إضافة دالة البناء في السطر الثاني ؛ أنظر إلى تعريف دالة البناء : 

CODE1. student::student (int a ): NumberOfCourses(a)
2. {
3. gradesOfCourses = new float [NumberOfCourses];
4. }
لقد قمت الآن بتعـديل عـدد مواد الطالب ؛ سينتج عـن هذا التعـديل تعـديلات أخرى في التركيب student ، على العـموم سأكتب البرنامج كله وركز الآن إلى كيفية استخدام الدالة main( ) ، وكيف سنستخدم دالة البناء من خلالها ، وأيضاً إلى التعـديلات الجديدة:

كود:
CODE1. #include <iostream>
2. using namespace std;
3. 
4. 
5. struct student {
6. student(int);
7. char itsName[200];
8. int itsNumber;
9. float* gradesOfCourses;
10. float itsAvg;
11. void CalculatorOfAvg(int = 100);
12. int NumberOfCourses;
13. };
14. 
15. student::student (int a ): NumberOfCourses(a)
16. {
17. gradesOfCourses = new float [NumberOfCourses];
18. }
19. 
20. 
21. void student::CalculatorOfAvg(int m)
22. {
23.  for(int i = 0;i < NumberOfCourses;i++) {
24.   cout << "Enter the grade of course" << i+1 << ":\t";
25.   cin >> gradesOfCourses[i];
26.  }
27.  float total=0;
28.  for( i=0; i< NumberOfCourses;i++)
29.   total+=gradesOfCourses[i];
30. 
31.  int avg=total/NumberOfCourses;
32. 
33.  itsAvg = (avg*m) /100;
34. }
35. 
36. int main()
37. {
38.  cout << "Enter The Number Of Courses\n";
39.  int i=0;
40.  cin >> i;
41.  student TheStudent(i);
42.  cout << "Enter The Avg u want to calcualtor\n";
43.  cin >> i;
44.  TheStudent.CalculatorOfAvg(i);
45.  cout << endl << TheStudent.itsAvg << endl;
46. 
47.  return 0;
48. }
أنظر إلى السطر 41 وكيف استخدمنا دالة البناء:
CODE41. student TheStudent(i);لقد وضعـنا متغير i من النـوع int بين قوسين ، والسبب في ذلك هـو أن أول دالة يقوم المترجم باستدعائها حينما تكون تعـمل على أحد الـتراكيب أو الـ structure ، هـي دالة البناء ؛ الآن لنفرض أنني استبدلت السطر 41 بهذا السطر ؛ فهل سيقوم المترجم بعـملية الترجمـة له:

كود:
CODE41. student TheStudent();
الجواب هـو لأ ؛ والسبب في ذلك عـدم وجود دالة بناء لا تستقبل وسائط ، فدالة البناء الموجودة في السطر 6 من الكـود السابق ، يجب أن تستقبل بارامتراً واحداً ، تستطيع حل هذه المشكلة بجعل هذا البارامتر الوحيد بارامتراً افتراضياً .
لقد انتهينا الآن من دالة البناء ، ويبقى لدينا موضوع أخير هـو دالة الهـدم.
دالة الهـدم هي عكس دالة البناء ، فبدلاً من أن تقوم ببناء التركيب أو الصنف فإنها تقوم بهـدمـه وإلغاء الذاكرة التي تم حجزها ، هذه الدالة تحمل نفس اسم التركيب الذي ستهـدمـه مسبوقاً بهذه العلامـة ( ~ ) ، تذكر أن هذه الدالة لا تعيد أية قيمـة ولا تستقبل أية وسائط.
أنظر الآن إلى شكل التركيب بعـد إضافة دالة الـهـدم إليه:

كود:
CODE1. struct student {
2. student(int);
3. ~student();
4. char itsName[200];
5. int itsNumber;
6. float* gradesOfCourses;
7. float itsAvg;
8. void CalculatorOfAvg(int = 100);
9. int NumberOfCourses;
10. };
حسناً ، هل تعرف الآن ماهي وظيفة دالة الهـدم ، أنظر إلى الأسطر التالية التي سينتج عـنها إحدى المشاكل:

كود:
CODE
1. student* a = new student (3);
2. delete a;لقد تم إنشاء مؤشر وحجز ذاكرة له ، وتم تمرير العـدد 3 ، لدالة البناء ، ولكن أنظر إلى السطر الثاني والذي سيقوم بإلغاء تخصيص الذاكرة، هل هذا يعـني أن العضو المتغير المؤشر gradesOfCourses (وهي مصفوفة حجمها الآن 3 عـناصر) سيتم إلغاؤها ، الجواب هـو لأ ، وعليك الآن القيام بتعريف دالة الهدم التي ستلغي هذا الحجز نهائياً .
هـناك سؤال آخر يجدر بك السؤال عـنه: وهـو متى ستستدعى دالة الهـدم حتى أضمن أنها ستقوم بإلغاء حجز الذاكرة للمؤشر gradesOfCourses ؛ والجواب عـنه هـو أنها ستستدعى عـند انتهاء البرنامج من التنفيذ أو عـند تحرير (إلغاء) الذاكرة لمؤشر من التركيب student ، أي الحالات التي تعـني أن المتغير من نمط التركيب student ينبغـي هـدمـه ؛ أنظر الآن إلى تعريف دالة الهـدم:

كود:
CODE1. student::~student ()
2. {
3. delete [] gradesOfCourses;
4. }

الخلاصـة:
تعلمت في هذا الدرس على الفرق بين التركيب والمتغير الذي يتم تعريفـه على نفس نمط التركيب ، تعرفت على دالتي البناء والهـدم وما هي مميزات الاثنتين والفروق بينهـما ، تعرفت أيضاً على كيفية تغيير عـدد المواد في التركيب student عبر دالة البناء ، وليس عبر الدالة main ؛ الدرسان السابقان ضروريان للغاية إذا ما أردت فهـم الكائنات وما تعـنيه .

عبد الله الساهر غير متواجد حالياً
قديم 21-10-2005, 07:53 AM   #4

الصورة الرمزية عبد الله الساهر

 رقم العضوية :  1
 تاريخ التسجيل :  22-07-2004
 المشاركات :  70,777
 الدولة :  ムレ3乃乇乇尺
 الجـنـس :  ذكر
 العمر :  38
 عدد النقاط :  243859
 قوة التقييم :  عبد الله الساهر تم تعطيل التقييم
 SMS :

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

 اخر مواضيع » عبد الله الساهر
 تفاصيل مشاركات » عبد الله الساهر
 أوسمة و جوائز » عبد الله الساهر
 معلومات الاتصال بـ عبد الله الساهر

افتراضي


الدرس الثالث
الكبسلـة

لقد وصلنا الآن إلى أحد مبادئ البرمجـة الكائنية ؛ وهي الكبسلة أو إخفاء المعلومات( إخفاء المعالجـة)...
قبل كل شيء أريد إيصال فكرة مهـمـة للغاية إليك ؛ هل تتذكر حينما كنت في المدرسـة وابتدأوا بتعليمك مادة قواعـد اللغـة العربية (النحـو) ؛ حسناً لقد قالوا لك أن المبتدأ في الجملة الاسمية يجب أن يكون مرفوعاً دائما ؛ مثل الجملة: البرمجـة شيء رائع ؛ هل قالوا لك السبب ؛ أو دعـني أصيغ السؤال بطريقة أفضل : هل من الضروري أن تعرف السبب ؛ الجواب لا يحتاج أن تعرف السبب إلا إن أردت أن تكون متخصصاً بعلم النحـو والصرف ؛ لقد كان من الضروري حينما ابتدأوا بتعليمك قواعـد اللغـة العربية في المدرسـة أن يقولوا لك إلتزم دائماً بالقواعـد فالجملة السابقة لا يجوز أن تقوم بتعـديلها إلى ، البرمجـةَ شيئاً رائعٌ (بفتح المبتدأ) ؛ هـنا الأمر ينطبق نفسـه على البرمجـة الكائنيـة ؛ وهذه هي ربما ليست قاعـدة ولكن أعتبر أنها أسلوب برمجي مهـم للغاية (وأشدد على كلمـة مهـم) :


QUOTE
كل ما هـو ليس ضرورياً أن يصبح واجهـة فعليه أن يكون مخفياً أو عضواً خاصاً ضمن الكائن


قد تقول لماذا هذه القاعدة مهـمـة ؛ دعـك الآن من طرح هذا السؤال فستعرف الفائدة لاحقاً ، وإن كـنت قضيت الدرسين السابقين أحاول أن ألمح إلى هذه القاعـدة ؛ الآن دعـني أدخل في الشرح العـملي لما قلته من كلام نظري.

أنظر إلى تعريف التركيب student :
CODE
كود:
1. struct student {
2. student(int);
3. ~student();
4. char itsName[200];
5. int itsNumber;
6. float* gradesOfCourses;
7. float itsAvg;
8. void CalculatorOfAvg(int = 100);
9. int NumberOfCourses;
10. };
دعـنا الآن نقرر من هـو الذي لا نحتـاجـه ونريد أن يصبح مخفياً أو عضواً خاصاً ؛ الجواب وحسب الشكل الحالي للتركيب هـو هؤلاء المتغيرات الأعضاء:
CODE
كود:
1. float* gradesOfCourses;
2. float itsAvg;
المتغير في السطر الأول ، فيم تحتـاجـه ، إذا أردت تغيير حجم المواد ، فبإمكانك فعل ذلك عن طريق دالة البناء ، المتغير في السطر الثاني لا تحتاجـه لأن الدالة CalculatorOfAvg ، هي من ستقوم بحساب هذا المتغير Avg ، وليس أنت.
الآن لنأتي إلى الصعيد الكـودي ، كيف نقوم بإخفاء المتغيرين السابقين عـن الواجهـة أو كيف نقوم بجعلها أعضاء خاصـة ؛ الجواب هـو عـن طريق الكلمـة المفتاحية private ؛ أنظر إلى كيفية استخدام هذه الكلمة:

CODE
كود:
1. struct NameOfStructure 
2. {
3.  //  هذه الأعضاء أعضاء عامـة 
4.  private :  // هذه هي الكلمـة الدليلية التي ستجعل جميع الأعضاء تحتها أعضاء خاصة
5.  //  أكتب هـنا الأعضاء الذين تريد جعلهـم أعضاء خاصـة
6. };
الآن دعـنا نطبق هذه التقنية الجـديدة على التركيب student ؛ أنظر الآن إلى التغيير الحاصل في التصريح عـن هذا التركيب:
CODE
كود:
1. struct student {
2. student(int);
3. ~student();
4. char itsName[200];
5. int itsNumber;
6. void CalculatorOfAvg(int = 100);
7. int NumberOfCourses;
8. private:
9. float* gradesOfCourses;
10. float itsAvg;
11. };
أنظر إلى السطر 18 ، الآن كل ما تحت السطر 18 من أعضاء سيصبحـون أعضاء مخفيين أو خاصين داخل التركيب student ...
بعـد أن انتهينا من الصعيد الكـودي ؛ عليك الآن معرفة الفرق بين الأعضاء الخاصـة والأعضاء العامـة ، قم الآن بكتابة هذه الأسطر داخل الدالة main( ) بعـد أن قمنا بتضمين التركيب الجـديد:
CODE
كود:
1. student a(10);
2. cout << a.itsAvg;
لن يقوم المترجم بترجمـة السطر 2 ؛ وسيقول لك أن هـناك خطأ ؛ هل تعرف ما هـو الخطأ ؛ إذا رجعت إلى تصريح التركيب student ؛ فستجد أنـه يخبرك أن العضو المتغير itsAvg هـو عضو خاص ؛ هل تعرف الآن ما معـنى عضو خاص ؛ العضو الخاص داخل أي تركيب ، لا يمكن الوصول إليه إلا من خلال التركيب نفسـه .....
قد تتساءل إذاً كيف سيكون بإمكاني طباعـة قيمـة المتغير itsAvg ، وإذا لم أستطع تنفيذ السطر 2 فما هي الفائدة أصلاً من التركيب student ، ألم يكن من الأفضل لو جعلت المتغير itsAvg متغيراً عاماً ؟ .
سؤال دائماً ما يسأله المبتدئون ؛ عـموماً هـناك أسلوب أو قاعـدة برمجية معروفة دائماً وهـي:
إذا قمت بجعل أحد المتغيرات خاصـة فقم فوراً بتوفير محددات الوصول إليها.

محددات الوصول:
ماهي محددات الوصول التي ستحل لي المشكلة السابقـة ، حسناً محددات الوصول هي التي تسمح لك بالوصول إلى المتغيرات الخاصة ، محددات الوصول هي عبارة عـن دالتين ، الدالة الأولى واسمها Get والثانية هـي Set ؛ كيف سأستخدم هذه الدوال؟ ، الجواب هـو أن تقوم بتوفير دالتين الأولى اسمها Get ثم اسم المتغير الخاص ، والثانية اسمها Set ثم اسم المتغير الخاص.

المحدد Get :
أود أن أشير هـنا إلى أنـه ليس هـناك كلمـة دليلية مثل Get و Set ؛ الذي أحدده هـنا هـو أسلوب برمجي متعارف عليه ، وهـو الأفضل ؛ فإذا ما أردت لكائناتك أن تكون مستقرة وقويـة فعليك باعتماد هذا الأسلوب الناجع.
المحدد Get لا يستقبل أي بارامتر ولا يحوي سوى أمر وحيد هـو أمر إعادة المتغير الخاص ، فلنقم الآن بتوفير محدد وصول إلى المتغير itsAvg من التركيب student ، أنظر:
CODE
كود:
1. int student::GetitsAvg()const
2. {  return itsAvg; }
وبالتالي فبإمكاننا تعـديل مشكلة الطباعـة في الكود السابق لتصبح هـكذا بعـد التعـديل:
CODE
كود:
3. student a(10);
4. cout << a.GetitsAvg();
بالرغـم من أن الأمر يرجع إليك في تحـديد من هـو العضو الخاص والعام ، إلا أن نصيحتي لك هـي أن تقوم بإخفاء جميع المتغيرات كلها وبتوفير محددات الوصول لكل متغير عضو خاص، أعتبر هذا الأمر قاعـدة أو حتى مسلمـة وستعرف لماذا فيم بعـد .... سنطبق هذه المسلمـة على جميع التركيب student ، أنظر الآن إلى الشكل الجـديد للتركيب:
CODE
كود:
1. struct student {
2.  student(int);
3.  ~student();
4.  int GetitsNumber()const; /*  يوجد تعـديل هـنا */
5.  int GetNumberOfCourses()const; /* يوجد تعديل هنا */
6.  float GetitsAvg(); /* يوجد تعديل هنا */
7.  float GetgradesOfCourses(int)const; /* يوجد تعـديل هنا */
8.  void CalculatorOfAvg(int = 100);
9.  char itsName[200];
10. private:
11.  float* gradesOfCourses; /* جعلنا هذا المتغير خاص */
12.  float itsAvg; /* جعلنا هذا المتغير خاص */
13.  int NumberOfCourses; /* جعلنا هذا المتغير خاص */
14.  int itsNumber; /* جعلنا هذا المتغير خاص */
15.  };ل
قد جعلنا جميع المتغيرات الأعضاء خاصـة ، وقمنا بتوفير محدد وصول لكل منها عـن طريق المحدد Get ، لاحظ أن طريقة عـمل هذا المحدد تختلف بالنسبة للمؤشر gradesOfCourses لاحظ أيضاً أننا لم نقـم بتوفير محدد وصول Get للمصفوفة الحرفية itsName ، والسبب في ذلك هـو طبيعـة هذه المصفوفة أي أن الأمر صعوبات كـودية فقط وليست تصميميـة ، ومن الآن فلاحقاً سيتم حذف هذه المصفوفة من هذا التركيب ، وربما سنستبدلها بإحدى المتغيرات string ، إذا وصلنا إلى تلك المرحلة المتقدمـة من الدروس...
هـناك ملاحظة مهمـة للغاية وهي أن الدالة get دالة ثابتـة ، احرص دائماً على أن تكون const وإلا فإن أخطاء كثيرة ستظهر دون أن تعرف سببها وخاصـة في المترجمات الجـديدة


المحدد Set :
لنفرض أنك قمت بتسليم هذا التركيب للمبرمج الذي طلبه منك ، وقد أعجب منـه عجباً شديداً للغاية ، ولكنـه أتى إليك في أحد الأوقات ، وقام بتوجيه هذا السؤال أو المشكلة إليك:
لقد حاولت جعل المستخدم يقوم بتغيير درجات مواده بعـد أن ينتهي من كتابتها ، ولكن لا حل لهذه المشكلة ، فالتركيب student لا يقبل السطر الثالث من هذا الكـود:
CODE
كود:
1. student a(10)
2. a.CalculatorOfAvg(5);
3. cin >> a.gradesOfCourses[4];
هل تعرف لماذا لا يقبل المترجم السطر الثالث ، السبب كما قلت في نفس هذا الدرس هـو أن المؤشر gradesOfCourses أصبح متغيراً خاصاُ وليس عاماً أي أن الوصول إليه محدد من داخل التركيب وليس من خارجـه.
ما هـو الحل إذاً ؛ الحل هـو أن تقوم بتوفير محدد وصول آخر هـو Set ، هذه الدالة أو المحدد لا تقوم إلا بتعـديل المتغير الذي تصل إليه ، وهي لا تعيد أي قيمـة أي من النـوع void ، ولكنها تستقبل وسيط واحد وحسب ، هـو القيمـة الجـديدة التي تنوي تعـديلها مكان قيمـة المتغير القديمـة ، وأيضاً هـناك قاعـدة جـديدة هي: دائماً إذا قمت بجعل أحد المتغيرات متغيراً خاصاً فعليك بتوفير محدد وصول آخر إليه هـو المحدد Set ، أنظر الآن إلى الشكل الجديد للتركيب:
CODE
كود:
1. struct student {
2.  student(int);
3.  ~student();
4.  int GetitsNumber()const; 
5.  int GetNumberOfCourses()const;
6.  float GetitsAvg()const; 
7.  float GetgradesOfCourses(int)const; 
8.  void SetitsNumber(int ); /* يوجد تعـديل هنا */
9.  void SetNumberOfCourses(int); /* يوجد تعـديل هنا */
10. void SetItsAvg(float ); /* يوجد تعـديل هنا */
11. void SetgradesOfCourses(int , float); /* يوجد تعـديل هنا */
12. void CalculatorOfAvg(int = 100);
13. private:
14.  float* gradesOfCourses; 
15.  float itsAvg; 
16.  int NumberOfCourses; 
17.  int itsNumber;
18.  };
هـناك أربع دوال إضافية جديدة لجميع المتغيرات الخاصـة الأربعـة ، سنقوم الآن بكتابة تعريف جميع الدوال ، بالنسبة للدالة الرابعـة والأخيرة فيجب التركيز جيداً عليها لأنها شاذة عـن بقية الدوال ، أنظر:

كود:
CODE
1. void student::SetitsNumber(int a) { itsNumber=a;} 
2. void student::SetNumberOfCourses(int a)
3. { NumberOfCourses=a; }
4. void student::SetItsAvg(float a) {itsAvg=a;} 
5. void student::SetgradesOfCourses(int d, float a)
6. { gradesOfCourses[d] = a;}
أنظر إلى الدالة في السطر الأول وهـي SetitsNumber ، هذه الدالة تقوم بتغيير قيمـة المتغير العضو itsNumber بالقيمة الجـديدة a أو البارامتر الممرر إليها ، كذلك الأمر بالنسبة للدالة في السطر الثاني والسطر الرابع ، بالنسبة للدالة الرابعـة في السطر الخامس ، فهـي تقوم بحل مشكلـة المبرمج السابق الذي ضربناه كمثل لك في هذا الدرس ، وهـي أنها تقوم بتغيير أي درجـة أدخلها الطالب وعليه فإن هذه الدالة تستقبل بارامترين اثنين ، الأول هـو دليل المصفوفة gradesOfCourses ، أو رقم المادة ضمن المصفوفة ، والبارامتر الثاني هـو القيمـة الجـديدة لذلك العـنصر ضمن المصفوفـة....

لقد انتهيت الآن ، من فهـم محددات الوصول ، لقد قمت بشيء كبير للغاية ، بالرغـم من أنك لا تدرك أهـميته ، لذلك أريد منك أن تنتبه جيداً حتى تفهـم فائدة الكبسلة (أو إخفاء البيانات) لأن هذا الكلام الذي سأكتبه لم أجد كتاباً طوال فترة تعليمي لهذه اللغـة يشرحه بالشكل المطلوب.
لنفترض أنك تعـمل في إحدى الشركات لصناعـة البرمجيات ، وأنه بالفعل طلب منك برمجـة نظام أو برنامج لحساب درجات الطلاب ، وقد قمت بالفعل باستخدام التركيب student الذي استخدمناه في هذا الدرس ، ثم بعـد عـدة سنوات ، طلبت الشركـة التي تعـمل فيها من فريق مبرمجين (لست أنت من ضمنهـم) برمجـة نظام لطلاب الكليات العسكرية ، وقد كلف الفريق أحد المبرمجين بالاعتناء بشؤون الطلاب في هذا النظام ، الذي سيفعله هذا المبرمج أنه سيذهب إلى البرامج السابقـة التي قامت بإنشاءها الشركـة ، ليبحث عـن كائنات (أو تركيبات في هذا المثال) من المفيد أن يستخدمها في نظامها ، وقد اختار هذا المبرمج التركيب الذي قمت أنت بكتابته قبل ثلاث سنوات ، أنظر ماذا سيفعله هذا المبرمج ، هذا المبرمج وجميع المبرمجين الآخرين لن ينظر إلى كامل التركيب الذي قمت بإنشاءه بل إلى واجهـة التركيب ، لن ينظر إلى تعريفات الدوال أو المتغيرات أو بمعـنى أصح لن ينظر إلى كيف عالجت هذا التركيب، أي أن المبرمج سينظر إلى هذا الجزء من التركيب student :
CODE
كود:
19. struct student {
20. student(int);
21. ~student();
22. int GetitsNumber()const; 
23. int GetNumberOfCourses()const;
24. float GetitsAvg()const; 
25. float GetgradesOfCourses(int)const; 
26. void SetitsNumber(int );
27. void SetNumberOfCourses(int); 
28. void SetItsAvg(float ); void SetgradesOfCourses(int , float); 
29. void CalculatorOfAvg(int = 100);
30. private:
31.  float* gradesOfCourses; 
32.  float itsAvg; 
33.  int NumberOfCourses; 
34.  int itsNumber;
35.  };
الآن أود أن أشير هـنا إلى قاعـدة مهـمـة للغاية:

QUOTE
المبرمجـون الذين يفكرون بطريقة كائنية يقومون ببرمجـة الواجهـة وليس المعالجـة.


أي أن هذا المبرمج الذي ينظر إلى تركيبك لن يفكر أبداً بكيفية معالجتك لحساب الدرجات ، فحسب الواجهـة للتركيب الذي قمت أنت بإنشاءه فإنك تقول لمن يريد أن يستخدم تركيبك: إذا أردت حساب معدل الدرجات ، فعليك باستخدام الدالة CalculatorOfAvg ، وقم بتمرير الدرجـة النهائية إلى هذا الدالة ، وتقول أيضاً حسب الواجهـة ، إذا أردت معرفة درجـة أي مادة حصل عليها الطالب ، فعليك باستخدام الدالة GetgradesOfCourses ، مع تمرير رقم المادة إلى الدالة...
لنفرض الآن أنك قلت لنفسك قبل قراءة أي درس من هذه الدروس أني لست بحاجـة للبرمجـة الكائنية وأني أستطيع فعل ما أريد دون الحاجـة إلى هذه التفاهات ، أنظر إلى تركيب student بلغـة السي:
CODE
كود:
1. struct student {
2. float* gradesOfCourses; 
3. float itsAvg; 
4. int NumberOfCourses; 
5. int itsNumber;
6. };
هل تعرف الآن ماذا سيفعله المبرمج الذي ظل يبحث عـن تركيب للطلاب ، هـو أنه الآن إذا أراد استخدام تركيبك أن يقوم بحساب الدرجات بنفسـه وأن يقوم بتعيين حجم المواد بنفسه وأن يفعل ويفعل ... بالتالي ما هي الفائدة من التركيب الذي قمت بإنشاءه ، أيضاً التركيب الذي قمت بإنشاءه لن يفهـمه أحد ، فمثلاً المتغير في السطر الخامس وهـو itsNumber والذي تقصد به الرقم التسلسلي للطالب ، قد يفهـمه أحد المبرمجين على أنـه تاريخ أو الرقم الجامعي أو ربما أي شيء آخر والأمر ينطبق نفسـه على المتغيرات السابقـة......
هل فهـمت الآن ما هـو الفرق بين الواجهـة والمعالجـة... وأيضاً الفرق بين النظرة الكائنية للبرمجـة والبرمجـة الهيكلية ، وكيف تقوم البرمجـة الكائنية بتوفير الكثير عليك.
تذكر: عليك بالتركيز على الواجهات وليس المعالجـة

انتهى الدرس الثالث ، إذا لم تفهـم بعض الأجزاء من هذا الدرس بالرغـم من إعادة قراءتك له لأكثر من مرة فالسبب هـو أن بعض هذه المفاهيم لن تفهـمها إلا بالممارسة العـملية....

عبد الله الساهر غير متواجد حالياً
قديم 21-10-2005, 07:55 AM   #5

الصورة الرمزية عبد الله الساهر

 رقم العضوية :  1
 تاريخ التسجيل :  22-07-2004
 المشاركات :  70,777
 الدولة :  ムレ3乃乇乇尺
 الجـنـس :  ذكر
 العمر :  38
 عدد النقاط :  243859
 قوة التقييم :  عبد الله الساهر تم تعطيل التقييم
 SMS :

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

 اخر مواضيع » عبد الله الساهر
 تفاصيل مشاركات » عبد الله الساهر
 أوسمة و جوائز » عبد الله الساهر
 معلومات الاتصال بـ عبد الله الساهر

افتراضي


ملحق بالدرس الثالث:

لنفترض أنك أحد المبرمجين المستقلين ، وأن إدارة إحدى المدارس طلبت منك تصميم برنامج للدرجات لكي يستخدمه المعلمين فحسب ، هذا البرنامج يقوم بتحرير درجات الطلاب وجلب المعلومات الإحصائيـة لكل تقدير في كل مادة ، أي برنامج بسيط وليس نظام متكامل ؛ هـناك طريقتين للقيام بذلك وكلا الطريقتين تعتمد على كيفية تفكيرك ....
طريقة غير كائنية المنحـى:
في البداية يجب عليك أن تقوم بإنشاء الكود من الصفر ، يجب عليك الاهتمام بقضية المؤشرات والدوال وكل شيء ، فمثلاً ربما ستقوم بتعريف تركيب stuct للطالب الواحد وعـن طريق صفوف التأشير الذاتي سيكون لديك ما يمكن أن نطلق عليه قاعـدة بيانات للطلاب ، أيضاً ستقوم ربما بكتابة دالة للتعامل مع الملفات وأخرى لإيجاد المعلومات الإحصائيـة ، وهـناك الكثير الكثير من القضايا التي ستهتـم بها ...... من الممكن أن نلخص هذه الاهتمامات التي ستهتم بها في كلمـة واحدة هـي معالجـة البيانات أو المعالجـة .
طريقة كائنيـة المنحى:
حسناً أول ما عليك التفكير فيه ، هـو الكائنـات التي ستكون موجودة في برنامجك ، أول كائن هـو الطالب وثاني كائن هـو المادة ، وثالث كائن ربما يكون القائمة المرتبطة التي ستقوم بإنشاء ما يمكن أن نطلق عليه قاعـدة بيانات للطلاب ، المبرمج الذي يفكر بطريقة كائنية المنحـى ليس عليه التفكير في قضية المعالجـة فسيأتي وقتها لاحقاً ؛ الآن عليك أنت الذهاب إلى البرامج التي كتبتها سابقاً ، والبحث عـن كائنات البرنامج الذي ستقوم بكتابتـه وهي الطالب والمادة والقائمة المرتبطـة ، لنفترض أنك وجدت جميع الكائنات في برامج استخدمتها سابقاً ، يعتبر هذا الأمر جيداً للغاية ، الآن وبعـد أن وجدت الكائنات ماذا عليك أن تفعل؟ ؛ كمبرمج يفكر بطريقة كائنية عليك النظر الآن إلى واجهـة الكائن وليس معالجـة البيانات داخل الكائن ، بكلمات أخرى ، في كائن الطالب لن تنظر إلى كيفية حساب درجـة الطالب ، أو إلى قضية المؤشرات في كائن الطالب ، أو هل كائن الطالب صحيح أم خاطئ ،أنت لن تنظر إلى هذه القضايا ، لأنك أولاً تعتقد أن كائن الطالب أو كل كائن ستجـده هـو كائن مستقل وأنه مر بالعـديد من الاختبارات قبل أن يصل إلى يديك لذلك لن تنظر إلى مثل هذه القضايا ؛ الآن كما قلنا ستنظر إلى واجهـة كائن الطالب ، أو بشكل أدق الكائنات التي تندرج تحت التصنيف public ، لأنها هي الوجـه العام ، الآن وبعـد أن نظرت إلى جميع واجهـات كائنات البرنامج ، ماذا عليك أن تفعل ، كل ما عليك أن تفعله هـو الاهتمام بقضية التفاعل بين هذه الكائنات لينتج البرنامج الذي تريده.
قد يقول قائل؛ لنفترض أن المبرمج بحث في مكتبات البرامج السابقة التي قام ببرمجتها ولم يجد كائن الطالب مثلاً ، فماذا عليه أن يفعل ، الآن عليه أن يقوم بإنشاء كائن الطالب من الصفر ، ولكنه لن يكون مثل المبرمج الذي سيفكر بطريقة غير كائنية ، بل سيقوم أولاً بكتابة واجهـة الكائن ثم يهتـم بقضية المعالجـة ..... أي أن المبرمج الذي يعتمد الطريقة الكائنية سيفكر دائماً بالواجهات وليس معالجـة البيانات.

عبد الله الساهر غير متواجد حالياً
قديم 21-10-2005, 07:58 AM   #6

الصورة الرمزية عبد الله الساهر

 رقم العضوية :  1
 تاريخ التسجيل :  22-07-2004
 المشاركات :  70,777
 الدولة :  ムレ3乃乇乇尺
 الجـنـس :  ذكر
 العمر :  38
 عدد النقاط :  243859
 قوة التقييم :  عبد الله الساهر تم تعطيل التقييم
 SMS :

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

 اخر مواضيع » عبد الله الساهر
 تفاصيل مشاركات » عبد الله الساهر
 أوسمة و جوائز » عبد الله الساهر
 معلومات الاتصال بـ عبد الله الساهر

افتراضي


الدرس الرابع:
الكلمة المفتاحية class و public .
تعـدد أوجـه الدالات (التحـميل الزائد للدوال)

سنتعرف بداية على الكلمـة المفتاحية public في هذا الدرس وعلى الكلمـة class ، وعلى تقنية أخرى في الدوال تتميز بها السي بلس بلس عـن لغـة السي.
الكلمـة المفتاحيـة public (والتي تعـني عام) هي عـكس الكلمـة المفتاحية التي تعرفنا عليها في الدرس السابق وهي private (والتي تعـني خاص) المتغيرات والدوال الأعضاء التي تندرج تحت الكلمـة الدليلية public تقول لك بأن جميع أولئك الأعضاء هـم أعضاء عامـة وليسوا أعضاء خاصـة ، هذه الكلمة يتوقف عـملها عـندما تصل إلى الكلمـة الدليلية الأخرى private أو يتوقف التصريح عـن التركيب ...... أنظر إلى كيفية استخدام هذه الكلمـة المفتاحية :
CODE
كود:
1. struct NameOfStruct
2. {
3. public:
4. int m;
5. int j;
6. private:
7. float k;
8. float I;
9. };
التركيب NameOfStruct يتألف من أربعـة أعضاء الاثنان الأولان هـما عضوان عامان أما الباقيان الأخيران فهـما عضوان خاصان ..... لا بد وهـنا أن تطرح سؤال وهـو هل هـناك فرق بين إذا وضعـنا كلمـة public أو تركنـاها ؛ حسناً في التراكيب فإن الوضع الافتراضي هـو أن جميع الأعضاء في التركيب هـم أعضاء عامـة وليسوا أعضاء خاصـة ، مالم توجـد كلمـة private حينها تصبح جميع الأعضاء المندرجـة تحتها أعضاء خاصـة ، لاحظ أن التركيب في المثال السابق هـو نفسه في هذا التركيب:

CODE
كود:
1. struct NameOfStruct
2. {
3. int m;
4. int j;
5. private:
6. float k;
7. float I;
8. };
هذا هـو عـمل الكلمـة الدليلية public ، أتمنى منك أن تعرف عـملها حتى تتقن فائدتها فيما بعـد.

الكلمة الدليلية class :
الكلمـة class تعـني في اللغـة الإنجليزيـة صنف أو فصيل أو فئة وهي تقابل في لغـة السي بلس بلس الكلمـة struct ، في لغـة السي بلس بلس ليس هـناك أي فرق بين التراكيب والأصناف ، فكل ما ينطبق على الأصناف ينطبق على التراكيب ، ولا يوجد بين النوعين سوى فرق واحد فقط ، وهـو أن الوضع الافتراضي لأعضاء أي تركيب هـو الوضع العام أي public ، أما بالنسبة لأعضاء أي صنف فإن الوضع الافتراضي لحالتهـم هـو الوضع الخاص private ..... من الآن فصاعداً سأستغـني عـن الكلمـة الدليلية struct في هذه الدروس وأستبدلها بالكلمة الدليلة class ، ليس هـناك أي ميزة حتى أختار أحدهـما سوى أن الأمر ارتاح إليه ، كما أن الكلمة الدليلية struct تذكرني بلغـة السي حينما أكون أعـمل على لغـة السي بلس بلس ...

هـناك نصيحـة برمجيـة هامـة أخرى أود ذكرها ولو أن ليست من ضمن السياق ، كل ما هـو ليس ضرورياً أن يكون عضواً عاماً (حتى وإن كان دالة ) وأنا أعـني بليس ضرورياً أي ليس من ضمن الواجهـة فيجب أن تجعله عضواً خاصاً.

سنترك الآن الأصناف والتراكيب جانباً في بقية هذا الدرس وسنرجع إليها في الدرس القادم ؛ بقية هذا الدرس سنخصصها لميزة تتميز بها السي بلس بلس عـن السي في موضوع الدوال وهـو تعـدد أوجـه الدالات أو التحـميل الزائد للدوال.

التحـميل الزائد للدوال:ا
ستعرت هذه الفقرة بكاملها من كتابي الإكسير لأني لم أستطع أن أكتب شرحاً أفضل من شرحي السابق.
يعتبر هذا الموضوع هـو أول نـوع من أنـواع تعدد الاوجـه والتي هي ثلاثة أنـواع وتعدد الأوجـه أحد أساسيات البرمجة الكائنية ، وهذا يعـني أنـه لن يمكنك تطبيق هذا الموضوع على لغـة السي (إن وجد مترجمات للغة السي مستقلة عـن مترجمات السي بلس بلس).
كما قلت أن من أحد أهـم أهداف البرمجة الكائنية هـو الوصول إلى استقلالية الكود الذي تكتبه وإمكانية إعادة استخدامـه وسهولة فعل ذلك ، والتحـميل الزائد يعـد أحد الأساليب القوية لفعل ذلك.
التحـميل الزائد للتوابع يعـني وجود نسخ أخرى تحمل نفس اسم التابع الزائد التحميل ولكنها تختلف إما في عدد الوسائط أو نـوع الوسائط أو حتى ترتيب هذه الوسائط.
والفائدة من ذلك تظهر فيما لو فهـمت موضوع الوسائط الافتراضية ، فوجود الوسائط الافتراضية في التوابع يمكنك من استدعاء الدالة بطريقتين مختلفتين إحداها بدون ذكر قيم الوسائط الافتراضية والأخرى بتغيير قيم الوسائط الافتراضية ، لنفرض أنك قررت كتابة أحد التوابع وهـو التابع Find ، وتريد من هذا التابع أن يقوم بالبحث في أي مصفوفة يطلبها المستخدم مع العلم أن هـناك مشكلة كبيرة وهي كيفية جعل هذا التابع يتعامل مع جميع أنواع المصفوفات int و char و float ... وغيرها الحل الوحيد هـو أن تقوم بزيادة تحـميل التابع find ، أي ستصبح النماذج المصغرة لنسخ التابع find، هكذا:
CODE
كود:
int find (int [] , int );
char find (char [] , char);
float find (float [] , float );
وحينما تصل لمرحلة تعريف هذه التوابع ، فيجب عليك تعريف كل نموذج على حدة ولن يكفيك تعريف تابع واحد فحسب.
عليك أن تعلم أن التحميل الزائد لأي تابع يعـني أن هـناك إصدارات أو نسخ أو توابع أخرى تحمل نفس اسم هذا التابع ولكنها تختلف في الوسائط سواء في العدد أو النوع.
سنقوم الآن بتقليد التابع Abs الذي يعيد القيمة المطلقة لأي عدد تدخله من المكتبة stdio في لغـة C ، ولربما تقوم أنت بتطويره حتى يصبح أفضل من التابع الموجود في لغـة C :
CODE
كود:
1. #include <iostream>
2. using namespace std;
3. 
4. int Abs (int );
5. float Abs(float );
6. double Abs (double );
7. 
8. int main()
9. {
10.  int Int=0;
11.  float Float=0;
12.  double Double=0;
13.  
14.  cout << "Int:\t"; cin >> Int;
15.  cout << "Float:\t"; cin >> Float;
16.  cout << "Double:\t";cin >> Double;
17.  cout << endl << endl;
18. 
19.  cout << "Int:\t" << Abs(Int) << endl;
20.  cout << "Float:\t" << Abs (Float) << endl;
21.  cout << "Double:\t" << Abs(Double) << endl;
22.  cout << endl;
23. 
24.  return 0;
25. }
26. int Abs(int X)
27. {
28.  return X<0 ? -X : X;
29. }
30. 
31. float Abs(float X)
32. {
33.  return X<0 ? -X : X;
34. }
35. 
36. double Abs (double X)
37. {
38.  return X<0 ? -X :X;
39. }
• انظر إلى النماذج المصغرة للتوابع Abs( ) ، جميعها تأحذ أنـواعاً مختلفة وسيقوم المترجم حينما تقوم باستدعاء هذه التوابع بالبحث عـن التابع المناسب ، النماذج موجودة في الأسطر 3 و 5 و 6.
• في الأسطر 10 و 11 و 13 تم الإعلان عن ثلاث متغيرات من الأنواع int و float و double وتسمية كل متغير بنفس مسمى نـوعه ولكن بجعل الحرف الأول كبيراً والسبب في هذا الإجراء حتى تستطيع التفريق بينها في البرنامج
• تطلب الأسطر 14 و 15 و 16 منك إدخال قيم هذه المتغيرات ، حتى تستطيع فيما بعـد إيجاد القيمة المطلقة لكل عـدد.
• السطر 19 يقوم بطباعة القيمة المطلقة للمتغير من النـوع int ، وكما ترى فهـو يقوم بطباعة القيمة العائدة للتابع int Abs( ) ، وكما ترى فإن التنفيذ سينتقل إلى البحث عـن التابع المناسب لمثل هذا النوع من الوسائط والتابع الأفضل هـو في السطر 26 .
• في السطر 28 ، يقوم البرنامج بمقارنة العـدد الممرر (الذي نود إيجاد القيمة المطلقة له) مع الصفر وفي حال كان أصغر فإننا نعيد العدد ولكن بقيمة سالبة وبالتالي فعـندما تدخل العـدد -2 فإن المقارنة ستنجح وبالتالي سيقوم التابع بإرجاع القيمة بعـد إضافة السالب إليها أي ستصبح القيمة العائدة هـكذا - - 2 ، والتي رياضياً تساوي 2 ، أما في حال لم تنجح المقارنة أي أن العدد أكبر من الصفر أو مساوي له فسيعيد التابع نفس القيمة ويقوم التابع main( ) بطباعتها في السطر 19 .
• نفس الأمر سيحدث في السطرين 20 و 21 .

بالرغـم من سهولة هذا الموضوع إلا أنه يعتبر أحد أهـم الإمكانات في لغة السي بلس بلس وفي البرمجة الكائنية بشكل عام ، وخاصة حينما تبدأ في التعامل مع الكائنـات.

محاذير عـند التحـميل الزائد للتوابع:
هـناك بعض الأخطاء عـندما تقوم بالتحميل الزائد للتوابع ، والتي يغفل عـنها الكثيرون ، وهذه هـي أهـمها:
1- لن يكون بإمكانك زيادة تحـميل أي تابع اعتماداً على القيمة العائدة فقط ، تعتبر هذه الإعلانات عـن التوابع خاطئـة:CODE

كود:
int Abs(int , int );
float Abs( int , int );
والسبب بسيط وهـو أن المترجم لن يعلم أبداً ما هـو التابع الذي سيقوم باستدعاءه بالضبط ، لأن الوسائط هـي نفسها.
2- لن يكون بإمكانك زيادة تحـميل أي تابع في حال كانت له نفس قائمة الوسائط حتى وإن كانت بعض وسائطة افتراضية ، أنظر إلى هذا المثال:CODE

كود:
int function(int a ,int b);
int function(int a,int b ,int c=100);
والسبب أنه حين استدعاء هذا التابع بواسطـة وسيطين وليس ثلاثة فحينها لن يعرف المترجم أي تابع يستدعي.
3-أيضاً لن يكون بإمكانك زيادة تحـميل تابع على هذا الشكل:

كود:
CODEint function(int a);
int function(const int a);
تذكر لكي ينجح التحـميل الزائد للتوابع ، فعلى التوابع التي تحمل نفس اسم التابع أن تختلف في قائمة الوسائط سواء في العدد أو الترتيب أو النوع أو أي شيء آخر مع الأخذ بعين الاعتبار المحاذير السابقة.

قد تقول الآن بعـد انتهاء الدرس ما الذي استفدنـاه منـه ، الجواب هـو أنـه سيقوم بتزويدك بطرق وتقنيات جديدة لتطوير كائناتك

عبد الله الساهر غير متواجد حالياً
قديم 21-10-2005, 08:01 AM   #7

الصورة الرمزية عبد الله الساهر

 رقم العضوية :  1
 تاريخ التسجيل :  22-07-2004
 المشاركات :  70,777
 الدولة :  ムレ3乃乇乇尺
 الجـنـس :  ذكر
 العمر :  38
 عدد النقاط :  243859
 قوة التقييم :  عبد الله الساهر تم تعطيل التقييم
 SMS :

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

 اخر مواضيع » عبد الله الساهر
 تفاصيل مشاركات » عبد الله الساهر
 أوسمة و جوائز » عبد الله الساهر
 معلومات الاتصال بـ عبد الله الساهر

افتراضي


الدرس الخامس
دوال أكثر تقدماً...
زيادة تحـميل دالة البناء.....
دالة بناء النسخـة

دعـنا الآن نطبق الدرس السابق (التحـميل الزائد للدوال ) على الكائنـات ، هل بإمكاننا مثلاً أن نزيد تحـميل دالة البناء وأيضاً دالة الهـدم..
كما قلنا في الدروس السابقـة ، إن من إحدى خصائص دالة البناء ، هي قدرتها على استقبال أي عـدد من الوسائط ، إذاً فبإمكاننا أن نزيد تحـميل هذه الدالة ، دعـنا الآن نفكر بشأن زيادة تحـميل دالة الهـدم .. هل بإمكاننا زيادة تحـميلها ، ألم تفهـم من الدروس السابقة أن هذه الدالة ، لا تستقبل أي وسائط أبداً ، بالتالي فإنه لا يمكن زيادة تحـميلها.....
ما الذي سنستفيده من زيادة تحـميل دالة البناء ، الذي سنسفيده هـو التماسك ، أقصد تماسك الكائن الذي تقوم أنت بكتابتـه.....
يوجد في عالم البرمجـة الكائنيـة نوعان اثنان من المبرمجيـن ، الأول: هـو صانع الأصناف ، والثاني هـو مستخدم الأصناف ؛ النـوع الأول مهـمته الأساسية هي أن يقوم بصنع صنف متماسك للغاية وقابل للاستخدام بأية طريقـة ونحن في هذه الحالة من هذا النـوع ؛ والهـدف الأساسي هي أن نقوم بتسهيل مهـمـة مستخدم الصنف (أقصد الصنف الذي نقوم بكتابته) ، ماهي الطريقة التي بإمكاننا فعلها لتسهيل مهـمـة مستخدم الصنف ، هي أن نقوم بصنع واجهـة للصنف قوية ومتماسكـة لأقصى قدرة برمجية نملكها ، من ضمن القوة التي ستحسب لواجهـة الصنف الذي تقوم بكتابته هي أن تكون جميع الدوال جاهـزة للاستعـمال بأي عـدد ممكن من الوسائط وحتى بأي نـوع محدد من الوسائط....
من ضمن الدوال الأساسيـة هي دالة البناء ، على دالة البناء أن تكون قادرة على العـمل في أي ظرف ممكن ..... أنظر إلى صنف الطالب الذي قمنا بتطويره على مدى الدروس الأربعـة السابقـة:
CODE
كود:
1. class student {
2. public:
3.       student(int);
4.       ~student();
5.       int GetitsNumber(); 
6.       int GetNumberOfCourses();
7.        float GetitsAvg(); 
8.        float GetgradesOfCourses(int ); 
9.        void SetitsNumber(int ); 
10.  void SetNumberOfCourses(int); 
11.  void SetItsAvg(float ); 
12.  void SetgradesOfCourses(int , float); 
13.  void CalculatorOfAvg(int = 100);
14. private:
15.  float* gradesOfCourses; 
16.  float itsAvg; 
17.  int NumberOfCourses; 
18.  int itsNumber;
19.  };

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

كود:
CODE1. student a;
فإن المترجم لن يقوم بترجمـة ذلك السطر ، والسبب في ذلك هـو أن الصنف الذي قمت بكتابتـه يجب أن تستقبل دالة بناءه بارامتر واحد ، سيتذمر مستخدم الصنف من هذا الشيء وسيقوم بإجراء تعـديلات على صنف student ، مما يعـني الآن أنك قد قمت بانتهاك أحد أهـداف البرمجـة الكائنية ، وهـو زيادة الإنتاجيـة ، وقد يتوقف بناء النظام الذي يقوم بعـمله الفريق البرمجي حتى يتم تعـديل الصنف الذي قمت بكتابته ، حتى تستطيع أن تحل هذه المشكلـة عليك بزيادة تحـميل دالة البناء ، وحتى يكون السطر السابق صحيحاً أيضاً...
قم بإضافة دالة البناء الجـديدة (الزائدة التحميل) ضمن التصريح عـن الصنف ... وهذا هـو تعريف هذه الدالة الجـديدة:
CODE
كود:
1. student::student()
2. {
3. gradesOfCourses= 0;
4. NumberOfCourses= 0;
5. itsNumber=0;
6. }
تقوم هذه الدالة بتصفير أغلب المتغيرات الأعضاء ضمن تصريح الصنف student ، إلا أنه ستظهر هـنا مشاكل خطيرة وجمـة في هذا الصنف student ... والسبب في ذلك هـو ضعف التصميم لهذا الصنف ... لا أقصد هـنا أن المبادئ التي قضيت الدروس السابقة وأنا أؤكد عليها خاطئـة أو أنها غير ناجعـة .. ولكن السبب هـو أني قمت بانتهاك بعضها وأنا أقوم بتطوير هذا الصنف لأغراض تعليميـة ليس إلا ... ولأجل ذلك ، فسأوقف تطوير هذا الصنف student في هذه الدروس (بعـد درس أو درسين) ، وسأقوم أيضاً بترك مشروع لك لبناء صنف student آخر ...
الأسباب الخطيرة التي أدت لضعف تصميم هذا الصنف هـو أن مستخدم الصنف إذا قام بكتابة هذا السطر:

كود:
CODE1. student a;
فإنه سيقوم بتصفير المؤشر gradesOfCourses ، وبالتالي فلن يعـود بإمكانه إضافة مواد جـديدة حتى يتم احتسابها .... وهـناك أخطاء تصميمية كثيرة في هذا الصنف..
سيستمر هذا الصنف معـنا في هذا الدرس وربما الدرس القادم ... وربما أقوم بتعـديله حتى يستمر معـنا طيلة هذه الدروس..
كما قلنا لن يكون بإمكانك زيادة تحـميل دالة الهـدم بسبب أنها أصلاً لا تستقبل أي وسائط .......

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

دالة بناء النسخـة:
هذه الدالة هي دالة عاديـة للغـاية ولا فرق بينها وبين دوال البناء الأخرى ، ولكن المميز فيها هـي أنها تقوم ببناء نسخـة عـن نفسها ، لنرجع إلى الصنف student ، الذي قمنا ببناءه على مدى الدروس الأربعـة السابقـة ، إذا أراد مستخدم الصنف ، استخدام الأمر التالي:
CODE
كود:
1. student a(10);
2. a.CalculatorOfAvg( 4 );
3. student b=a;
الذي يعـنيني الآن هـو الأمر الثالث بالتحـديد ، والذي سينتج عـنه نسخ محتويات الكائن a إلى محتويات الكائن b ، لن يعترض المترجم على هذا الأمر وذلك لأنـه يزودك بالفعل دالة عضو (غير دالة البناء والهـدم) تقوم بعـمل المساواة ، ولكن دعـنا الآن نتحدث قليلاً عـن المشاكل التي ستظهر إذا قمت بتنفيذها في مترجمـك ...
لم أجرب هذا المثال في Visual C++ 6 وإنما جربتـه في Visual C++.Net ، وسبب ذكري للمترجمات التي أستخدمها حتى تفهـم أن بعض النتائج التي ستظهر لديك ستكون مخالفـة لما قد يظهر لدي والسبب اختلاف المترجمات ، نرجع إلى موضوعـنا إذا قمت بتنفيذ الأمر السابق وبالتحـديد في السطر الثالث ، فإن المترجم لن يعترض أبداً على ما تقوم بـه ولكن حينما يتجاوز السطر الثالث بأسطر قليلـة ينهار انهياراً تاماً ، وفي حال لم يكـن هـناك أي أسطر بعـد السطر الثالث فسينهار عـند نهاية البرنامج ، السبب في ذلك هـو الذاكرة وبالتحـديد في المؤشر gradesOfCourses ... قبل أن تقرأ الفقرة القادمـة حاول أن تخمن السبب وراء انهيار البرنامج ودور المؤشر gradesOfCourses في عـمل ذلك .........
من الأفضل أن تخمن السبب حتى تثبت لنفسك أنك تريد التعلم بالفعل وليس التلقي لكتابة أمثلـة تتفاخر بها أمام زملائك وأقرانك ؛ سنتحدث الآن عـن السطر الثالث ، والذي هـو بالشكل التالي:

كود:
CODEstudent b = a;
دعـنا نفكر قليلاً في ما تعـنيـه هذه العلامـة (علامـة الإسناد = ) ، أنك تقول فيها للمترجـم يا مترجم قم بأخذ جميع محتويات المتغيرات الأعضاء في الكائن a وضعها في المتغيرات الأعضاء في الكائن b ، وهذا ما يقوم به المترجم لن يكون هـناك أية مشاكل حينما تكون المتغيرات الأعضاء عبارة عـن متغيرات عاديـة تحـمل قيـم ، ولكن ماذا لو كانت هذه المتغيرات عبارة عـن مؤشرات تحـمل عـناوين في الذاكرة وليس قيـم ، سينتهي الأمر بأن المؤشر gradesOfCourses في الكائن a سيشير إلى نفس مكان الذاكرة الذي يشير إليه المؤشر gradesOfCourses في الكائن b ، أرجع إلى تعريفات الدوال الأعضاء وأنظر إلى تعريف دالة الهـدم سيتم إلغاء الذاكرة للمؤشر gradesOfCourses في حال تم هـدم البرنامج ، إن ذلك يعـني الآن أن أي كائن سيتم هـدمـه من بين الاثنين سيهـدم معـه الآخر ، وذلك يعـني أن أي تغيير في قيم المصفوفـة أو المؤشر gradesOfCourses في أحد الكائنين سينتج عـنه تغير القيم تلقائياً في الكائن الآخر ... السؤال كيف ستحل هذه المشكلـة ........
الجواب هـو القيام بكتابة دالة بناء النسخـة التي ستحل هذه المشكلـة نهائياً والتي أصلاً يزودك المترجم بها في حال لم تقـم بكتابة واحدة ........... أنظر إلى الإعلان عـن دالة بناء النسخـة:

كود:
CODEstudent (const student& );
لاحـظ أن دالة بناء النسخـة لها نفس اسم الصنف مما يعـني أنها دالة بناء في الأساس ، أنظر أيضاً إلى الوسائط التي تحملها ، إنها تحـمل مرجعية من النـوع student ،وهي ثابتـة const ، لا تنسى أن هذا هـو الشكل الأساسي لدالة بناء النسخـة ...... أنظر الآن إلى تعريف دالة بناء النسخـة ، وأنظر كيف سنقوم بحجز الذاكرة للمؤشر gradesOfCourses بشكل آمن لا تشوبه أي شائبـة ، أنظر وحاول أن تفهـم الكـود قبل قراءة باقي الدرس:
CODE

كود:
student::student(const studeVVUOTE
ملاحـظة:
لا تنسى أبداً أن تضع في جميع محددات الوصول Get الكلمـة const ، إذا لم تفعل ذلك فلن يعـمل دالة بناء النسخـة....



QUOTE
ملاحظـة:
البعض سيقوم بتجريب أمثلة وقد تعـمل لديه بسبب قدم المترجم الذي يملكـه (وحتى المترجمات الجـديدة تقبل هذه الأخطاء) ، مثل هذا الإعلان عـن دالة بناء النسخـة:
CODEstudent (const student rhs);هذا السطر لن يعـمل في أي مترجم سواء المترجمات القديمـة أو الجـديدة إلا إن كان المترجم الذي تستخدمـه للغـة أخرى غير لغـة السي بلس بلس......


انتهى الدرس الخامس ..........

عبد الله الساهر غير متواجد حالياً
قديم 21-10-2005, 08:05 AM   #8

الصورة الرمزية عبد الله الساهر

 رقم العضوية :  1
 تاريخ التسجيل :  22-07-2004
 المشاركات :  70,777
 الدولة :  ムレ3乃乇乇尺
 الجـنـس :  ذكر
 العمر :  38
 عدد النقاط :  243859
 قوة التقييم :  عبد الله الساهر تم تعطيل التقييم
 SMS :

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

 اخر مواضيع » عبد الله الساهر
 تفاصيل مشاركات » عبد الله الساهر
 أوسمة و جوائز » عبد الله الساهر
 معلومات الاتصال بـ عبد الله الساهر

افتراضي


الدرس السادس:
حالة دراسية (حساب بنك)
هذا الدرس يعتبر درساً مهـماً للغاية ، والسبب في ذلك هـو حتى تفهـم المبادئ الأساسية التي ذكرناها في

الدروس الخمسـة السابقـة ، وأيضاً هـناك معلومات أخرى مهـمـة للغاية .....

كما قلت سابقاً فإننا سنتخلى عـن الصنف student والسبب في ذلك أخطاء تصميميـة كثيرة ارتكبتها أنا

متعـمداً لأغراض تعليميـة فقط ...

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

نقوم بإنشاءه.....

لنفرض أنك تعـمل ضمن فريق يعـمل لإنشاء نظام بنكـي وقد قام رئيس الفريق بإسناد

مهـمـة إنشاء كائن الحساب البنكي إليك بالإضافـة إليك ، لم يطلب منك الكثير إلا أن المميز فيما طلبه منك

هـو أن تقوم بإنشاء عـداد يقوم بحساب الكائنات التي تُنشأ من هذا الصنف...

ملاحـظـة: ليس هذا ما يحدث لدى فريق مبرمجي ومصممي أي نظام ولكن نحن نتحدث هـنا عـن حالة

افتراضيـة لغرض التعلم فقط.....

عليك الآن أن تحدد نـوعـك من المبرمجين ... هل أنت صانع أصناف أم مستخدم أصناف .. كما هـو واضح

فأنت صانع أصناف .. وظيفتك أن تقوم بإنشاء صنف يستطيع مستخدمـه أن يقوم باستخدامـه بسهولة ودون

التفكير في قضية المعالجـة ....

فكّر الآن بكيفية تصميم هذا الصنف ، الحساب البنكي ، اسأل نفسك مما يتكون ... جميع ما سيحدث في هذا

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

أيضاً ... الجواب هـو أن العـميل هـو من يتكون من حسابات بنكيـة وليس العـكس ... سنتحدث في الدروس

القادمـة عـن هذه العلاقـة بشكل أعـمق وأكثر ....
صنف الحساب البنكي يتكون بصفـة أساسيـة من المال المـودع ، والذي يزيد وينقص ويتحـول ويسحب ،

اتفقنا الآن على وجود عضو اسمـه المال المودع ، العـنصر الثاني هـو تاريخ إنشاء هذا الحساب ، قد تسأل فيما نحتـاج هذا المتغير؛ الجواب هـو حتى يستطيع البنك خصـم مال الزكاة تلقائياً كلما مر حول (أو سنـة) كاملة ،

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

إن كان سيخصم مال الزكـاة أو لأ .... بما أن جميع هذه الأعضاء التي ذكرناها متغيرات فستكون مكبسلـة ،

أنظر إلى هذا الصنف:
CODE
كود:
1. class Account 
2. {
3. double money;
4. int DayOfBuilding; 
5. int MonthOfBuilding;
6. int yearOfBuilding;
7. int Day;
8. int Month;
9. int Year;
10. };

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

اتفقنا على عـنصر تاريخ إنشاء الحساب ، هذا العـنصر يتكون من ثلاث عـناصر هي يوم إنشاء الحساب

وشهر إنشاء الحساب وسنـة إنشاء الحساب ، وكلها في الأسطر 4 و 5 و 6 ... والأمر نفسـه بالنسبـة

لعـنصر تاريخ اليوم ، لتطوير الصنف علينا أن نقوم بإنشاء كائن اسمـه التاريخ Date ، يتكون من ثلاث

متغيرات هي اليوم والشهر والسنـة ... عليك أيضاً أن تقوم بكتابـة واجهـة قويـة لهذا الصنف ..... أنظر إلى

هذا الصنف

CODE
كود:
class Date
{
public:
getDay( ) { return day;}
getMonth( ) { return month;}
getYear( ) { return year;}
void setDay(int a) { day=a;}
void setMonth(int a) { month=a;}
void setYear(int a) { year = a;}
private:
int day;
int month;
int year;
};
الآن أنظر إلى كائن الحساب البنكي ولكن هذه المرة بشكل أكثر سهـولة:

CODE
كود:
class Account
{
double money;
Date DateOfBuilding;
Date ThisDay;
};

الآن علينا كتابـة محددات الوصول لهذا الصنف حتى يستطيع التفاعل مع الأصناف الأخرى ، لاحظ أن هذه

المحددات ستختلف طبيعـة عـملها مع ما تعلمناه سابقاً ، والأمر يرجع إلى طريقة تفكير المصمم أو إلى طبيعـة

عضو الصنف الذي نحاول كتابة محددات وصول إليه:

كود:
CODEclass Account
{
public:
getMoney() { return money;}
double getDateOfBuilding(int a=1) {
 switch(a){
  case 1: return DateOfBuilding.getDay();
  case 2: return DateOfBuilding.getMonth();
  case 3: return DateOfBuilding.getYear();
  default: return 0;
   }
}
double getThisDay(int a=1) {
 switch(a){
  case 1: return ThisDay.getDay();
  case 2: return ThisDay.getMonth();
  case 3: return ThisDay.getYear();
  default: return 0;
 }
}
void setMoney(double m) { m=money;}
void setDateOfBuilding(int a,int b,int c)
{
 DateOfBuilding.setDay(a);
 DateOfBuilding.setMonth(b);
 DateOfBuilding.setYear(c);
}
void setThisDay(int a,int b,int c)
{
 ThisDay.setDay(a);
 ThisDay.setMonth(b);
 ThisDay.setYear(c);
}

private:
double money;
Date DateOfBuilding;
Date ThisDay;
};

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

قد تختلف معـي في كيفية استخدام محددات الوصول get و set ، الأمر يرجع في النهايـة إليك ، ولو أن الأمر

أصلاً لا يتم بهـذه الطريقـة ولكننا ذكرناها بسبب تقدم هذا الموضوع عـن دروسنا بأشواط..........

أنظر إلى واجهـة الصنف الذي قمنا بإنشاءه ولنركز الآن على كيفية تطوير الواجهـة وطريقة استخدامـه:

كود:
CODEclass Account
{
public:
getMoney() { return money;}
double getDateOfBuilding(int =1);
double getThisDay(int =1);
void setMoney(double m);
void setDateOfBuilding(int a,int b,int c);
void setThisDay(int a,int b,int c);

private:
     double money;
     Date DateOfBuilding;
     Date ThisDay;
};
ينقص هذا الصنف بعض الدوال المهـمـة للغاية ، أولى هذه الدوال دوال البناء والهـدم...
دعـنا نفكر في كيفيـة بناء هذا الصنف حينما يقوم مستخدم الصنف باستخدامـه ، الطريقة الأولى أن يقوم ببناءه

بدون أي قيم ، الطريقة الثانية هي أن يقوم ببناءه بقيمـة الحساب البنكي ، الطريقة الثالثة هي أن يقوم ببناءه بقيمة

الحساب البنكي وتاريخ إنشاء الحساب هـناك طريقة رابعـة لن ننظر إليها وسأتركها لك .............. هـناك

أيضاً دالة بناء خامسـة وهي دالة بناء النسخـة ، سأتركها لك أيضاً ، سنقوم الآن بكتابة تعريفات دوال البناء

الثلاث بالإضافة إلى دالة الهـدم ..........

كود:
CODEAccount() {}
Account(double a):money(a) {}
Account(double a, Date b):money(a),DateOfBuilding(b){}
~Account() {}

لقد انتهينا الآن من دوال البناء ودالة الهـدم...
بقي لدينا الآن بعض الدوال الإضافية البسيطـة ، فالصنف الذي نقوم بكتابتـه غير قادر على التفاعل مع نظام

مصرفي بكامله ، لذلك علينا تطويره حتى يصبح قادراً على عـمليات الإيداع والتحـويل وغيرها .....
لعـملية الإيداع سنقوم بكتابة الدالة
كود:
CODEAddMoney()
لعـملية التحويل سنقوم بكتابة الدالة
كود:
CODEChang( )
هـناك مشاكل ستظهر ، لا عليك سنقوم الآن بكتابة تعريفات هذه الدوال:
CODE
كود:
void AddMoney(double a){
 money+=a;}
void change(double a,Account& b){
 money-=a;
 double c=b.getMoney();
 c+=a;
 b.setMoney(c);
}

لقد أصبح الآن الصنف Account يستطيع الإيداع والتحـويل ، الدالة AddMoney بسيطـة ولا تحتاج لشرح ،

الدالة chang تقوم باستقبال بارامترين اثنين ، الأول هـو كم المبلغ المراد تحويله والثاني هـو الحساب الذي

تريد التحـويل إليه، لن أشرح كيف ستقوم الدالة change بعـملها حتى لا نضيع الوقت في شرح خوارزميات

وطرق معالجـة.
هـناك مشكلـة ظهرت ، ماذا لو كان المبلغ الذي نريد تحـويله أكبر من مبلغ الحساب البنكي ، عليك الآن أن

تتأكـد من هذه المشكلـة أي أن المبلغ الموجود في الحساب أعلى من المبلغ المحـول كيف ستقوم بعـمل هذا

التأكـد ، من الخطأ أن تقوم بتضمين عـملية التأكد هذه ضمن الدالة change ، الدالة change وظيفتها هـي

تحـويل المال فقط ، ولا يهـمها التأكد أبداً ، لذلك من الضروري أن تقوم بتفويض هذه المهـمـة إلى دالة

أخرى ، وسنقوم بتسميتها ، سنقوم بتسمية هذه الدالة sureOfMoney :
CODE
كود:
bool sureOfMoney(double m)
{
 if (m>money) return false;
 else return true;
}

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

التأكد ستتم ضمن صنف آخر وليس بالضرورة هذا الصنف

تعـديل محددات الوصول:

لقد أخطأنا في محددات الوصول أخطاءً كثيرة شنيعـة وينبغي لنا تعـديلها ، الدالتين get و set يجب أن تكون

في نفس النمط الذي قمنا به في الدروس السابقـة ، سنقوم الآن بتعـديل هاتين الدالتين تعـديلاً بسيطاً للغاية

وهـو الذي كان من المفروض أن يتم منذ أول ما قمنا بتطوير هذا الكـود ، وسبب وضعـي لتلك النماذج هـو

حتى أقول لك أن هذه هي طريقة محددات الوصول الصحيحـة مـهما كان شكل العـناصر الذي تستخدمـه ولو

كانت على شاكلة الصنف Date ، أنظر الآن إلى الصنف بكامله مضمنين فيه التغييرات

الجـديدة..................

عبد الله الساهر غير متواجد حالياً
قديم 21-10-2005, 08:08 AM   #9

الصورة الرمزية عبد الله الساهر

 رقم العضوية :  1
 تاريخ التسجيل :  22-07-2004
 المشاركات :  70,777
 الدولة :  ムレ3乃乇乇尺
 الجـنـس :  ذكر
 العمر :  38
 عدد النقاط :  243859
 قوة التقييم :  عبد الله الساهر تم تعطيل التقييم
 SMS :

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

 اخر مواضيع » عبد الله الساهر
 تفاصيل مشاركات » عبد الله الساهر
 أوسمة و جوائز » عبد الله الساهر
 معلومات الاتصال بـ عبد الله الساهر

افتراضي


الكـود وفيه التغييرات الجـديدة:
كود:
CODEclass Account
{
public:
Account() {}
Account(double a):money(a) {}
Account(double a, Date b):money(a),DateOfBuilding(b){}
bool sureOfMoney(double m)
{
 if (m>money) return false;
 else return true;
}
void AddMoney(double a){
 money+=a;}
void change(double a,Account& b){
 money-=a;
 double c=b.getMoney();
 c+=a;
 b.setMoney(c);
}

getMoney() { return money;}
Date getDateOfBuilding( )const; //  حصل تغيير هـنا
Date getThisDay( )const; // حصل تغيير هنا
void setMoney(double m) { m=money;}
void setDateOfBuilding(Date ); // حصل تغيير هنا
void setThisDay(Date ); //  حصل تغيير هـنا
private:
      double money;
      Date DateOfBuilding;
      Date ThisDay;
};

أنظر الآن إلى تعريفات محددات الوصول الجـديدة والتي حصلت فيها التغييرات:
CODE
Date Account::getDateOfBuilding() const {return DateOfBuilding;}
Date Account::getThisDay() const { return ThisDay;}
/********************************************/
void Account::setDateOfBuilding(Date a) { DateOfBuilding=a;}
void Account::setThisDay(Date a) { ThisDay=a;}

بإمكانك الآن إضافـة دالة بناء النسخـة، في السابق قبل أن نقوم بكتابة محددات الوصول الجـديدة لم يكن بإمكانك كتابة دالة بناء النسخـة ، ولكن بعـد أن قمنا بكتابـة محددات الوصول بالشكل الصحيح أصبح بإمكانك كتابة دالة بناء النسخـة.....

هل انتهينا من تطوير هذا الصنف أم بقي هـناك القليل ... حسناً الصنف بهذا الشكل يحتاج للكثير حتى تقوم بتطويره ، سأترك لك هذه المهـمـة .... أما الآن فسنناقش ما كتبناه في بداية هذا الدرس حينما طلب منك رئيس الفريق أن تحدد له عـدد الكائنـات التي أُنشئت من صنفـك .. فكر في كيفية القيام بهذه الطريقـة...
هـناك طريقـة وهي أن تقوم بكتابة صنف آخر يراقب صنف الحساب البنكي ويحسب عـدد الكائنـات ، وهذه طريقـة خاطئـة بالطبع فكما قلنا في الدروس السابقـة ، فيجب عليك كتابة صنف مستقل عـن تغييرات العالم الخارجي بذاته ونفسه وقدراتـه ، الحل هـو أن تقوم بكتابة عـدّاد أو متغير يزيد كلما قمت بإستدعاء دالة البناء وينقص كلما قمت بإستدعاء دالة الهـدم ، قد تقول أنه ليس من الممكن فعل ذلك ، فهذا المتغير سيكون ملك للكائن ولن يحسب بقية الكائنات الأخرى ، حسناً الجواب هـو أن تقوم بكتابة متغير الذي يملكـه هـو الصنف وليس الكائن ، وهذه هي الأعضاء الساكنـة ..... في القسم الخاص من الصنف Account قم بإضافـة هذا المتغير:

كود:
CODEstatic int count;
قم بتوفير محدد وصول له get في القسم العام ، على هذه الطريقـة:

كود:
CODEstatic int getCount() { return count;}
الآن عليك إضافة دالتي البناء والهـدم ، أنظر:
CODE
كود:
Account () { count++; }
~Account () {count--;}
قم أيضاً بكتابة نفس الإجراء في دالة البناء في بقية دوال البناء الأخرى
بقي أن نشير هـنا إلى أن المتغيرات الساكنـة لا تخـزن في الـ stack بل في ذاكرة الـ heap في مثل المكان التي تخزن فيه المؤشرات ، إذاً عليك أن تقوم بعـملية تهيئـة لهذا المتغير الساكن count ، أنظر:
كود:
CODEint Account::count = 0;
نقوم بكتابة هذا السطر خارج الصنف وليس داخلـه...

أنظر الآن إلى كيفية استخدام الصنف Account بشكله الجـديد في الدالة main :
كود:
CODEint main()
{
Account a[10];
cout << Account::getCount() << endl;

return 0;
}

الخلاصـة:
لقد تعرفت على محددات الوصول وقمت بتأكيد معلوماتك حولها .. وأيضاً على بعض الأخطاء التي يقع فيها المبتدئون .. تعرفت أيضاً على المتغيرات والدوال الساكنـة .......

عبد الله الساهر غير متواجد حالياً
قديم 27-10-2005, 11:03 PM   #10

الصورة الرمزية صمت الجمال

 رقم العضوية :  35
 تاريخ التسجيل :  06-09-2004
 المشاركات :  1,120
 العمر :  38
 عدد النقاط :  10
 قوة التقييم :  صمت الجمال is on a distinguished road
 اخر مواضيع » صمت الجمال
 تفاصيل مشاركات » صمت الجمال
 أوسمة و جوائز » صمت الجمال
 معلومات الاتصال بـ صمت الجمال

افتراضي


والله اللي يريد يتعلم


هاللغة ماعليه إلا بالعبير وبعبادي الاستاذ


جدا رائع اخوي

توقيع :




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


صمت الجمال غير متواجد حالياً
موضوع مغلق

مواقع النشر (المفضلة)


أدوات الموضوع
انواع عرض الموضوع

تعليمات المشاركة
لا تستطيع إضافة مواضيع جديدة
لا تستطيع الرد على المواضيع
لا تستطيع إرفاق ملفات
لا تستطيع تعديل مشاركاتك

BB code is متاحة
كود [IMG] متاحة
كود HTML معطلة
Trackbacks are متاحة
Pingbacks are متاحة
Refbacks are متاحة


المواضيع المتشابهه
الموضوع كاتب الموضوع المنتدى مشاركات آخر مشاركة
وقفات تربوية من سيرة الرسول في القرآن الكريم عزوف ۩ ۞ ۩ مجلس القرآن الكريم وعلومه ۩ ۞ ۩ 11 03-01-2018 04:12 AM
ابي مساعدتكم بنماذج الأكسل ندوي استفسارات شهادة تقنية المعلومات CIT 15 22-02-2017 01:13 AM
لقاح الإنفلونزا الموسمي أبكاني قرآن ربي مجلس الصحة والغذاء 8 28-08-2015 04:35 AM
أكثر المدن الصناعية كآبة في العالم "نوريلسك" Rassan روائع الفن التشكيلي والفوتغرافي 10 03-08-2015 11:28 PM
مشكلة ولدي وألي عنده حلي يفدني نصف الليل مجلس عـائـلـتـي 6 15-06-2014 01:23 AM


الساعة الآن 04:11 PM


Powered by vBulletin® Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO 3.6.0 TranZ By Almuhajir
Ads Organizer 3.0.3 by Analytics - Distance Education
جميع الحقوق محفوظة لـ : منتديات العبير
المحتوى المنشور فى موقع العبير لايعبر بالضرورة عن وجهة نظر الإدارة وإنما يعبر عن وجهة نظر كاتبها