>> الصفحة الرئيسية >> اساسيات لغة سي++ >> سي++ من المستوى المبتدئ الى المتوسط

الأقسام الرئيسية

 التنصيب والاعداد التنصيب والاعداد
 دروس متقدمة دروس متقدمة
 سلسلة دروس للمبتدئين سلسلة دروس للمبتدئين
 اساسيات لغة سي++ اساسيات لغة سي++
 مقالات ZetCode مقالات ZetCode
 

جديد الدروس

 الوحدة QtUiTools (واجهة المستخدم ديناميكية التوليد)
التاريخ 04/07/2009 الوحدة QtUiTools (واجهة المستخدم ديناميكية التوليد)
 Qt and Phonon
التاريخ 04/07/2009 Qt and Phonon
 تتمة الرسائل ومربعات الحوار في qt
التاريخ 04/07/2009 تتمة الرسائل ومربعات الحوار في qt
 مدخل الى xml في Qt
التاريخ 04/07/2009 مدخل الى xml في Qt
 الإدخال والإخراج لبيانات الفئات
التاريخ 04/07/2009 الإدخال والإخراج لبيانات الفئات
 

سي++ من المستوى المبتدئ الى المتوسط


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

سي++ تعتبر الأن اللغه الأساسيه في تطوير الكثير من المشاريع التجاريه والتعليميه أيضا ، والسبب لما تحتوي هذه اللغه من أمكانيات فهي تدعم مفهوم OOP ومفهوم Procedural Programming بالأضافه الى مفهوم الـ Generic Programming والتي من خلاله نستطيع عمل مكتبات يستخدمها الـ client بكل سهوله وبأي نوع من البيانات ..

كل هذه المفاهيم التي تدعمها Hybrid Langauge جعلتها اللغه المفضله للكثير من المبرمجين ومهندسي البرمجيات . ولكن بالمقابل جعلت عمليه تعلم اللغه أكثر غموضا عما كانت عليه في لغات أخرى كـ سي مثلا .

هذا المقال موجه للمبتدئين فقط ، أقصد بمبتدئ هو من يفهم الأساسيات في لغه سي++ ، من Operator Overloading ، من أبسط مفاهيم OOP وكيفيه استخدامها ، من exception وكيفيه استخدامه ..

قد تتسائل "هل أكون مبتدئ بعد أنهائي لكل هذا ؟" ، الجواب بالطبع تكون مبتدئ .. فاحتراف لغه كسي++ يحتاج الى ثلاثه مراحل :
1) تعلم الـ Syntax الخاص باللغه وكيفيه أستخدام الأمور السابقه ذكرها أعلاه .
2) كيفيه تحليل و تقسيم المشكله وكتابه كلاسات مكبسله بشكل جيد C++ Design ..
3) تعلم الأستخدام الأمثل لكل أداه ومتى لا يفضل استخدام بعض الأدوات ومتى يفضل ..

في المرحله الأولى كما ذكرت ، سوف تتعلم كيفيه عمل كلاس من نوع X ، كيفيه عمل كائن ، ربما ستدرك بعض من مفاهيم OOP بشكل جيد وتقوم بكتابه متغيراتك بشكل محمي private وتقوم بتوفير Accessory Function .. وسوف تستطيع استخدام الوراثه وسوف تعرف ما هو ال Polymorphism وما المقصود به ..

المرحله الثانيه ، وهي التي تحدد هل أنت مبرمج سي++ محترف أم مبتدئ ، وهي خاصه بكيفيه تقسيم البرنامج ، وكتابه كلاسات تتفاعل مع بعضها بشكل جيد .. مع مراعاه تغير المتطلبات Change of requirement فيما بعد والتي هي أمر مفروغ منه في عمليه تطوير البرمجيات Software Development .. متطلبات العميل تتغير مع مرور الزمن والتصميم الجيد لكلاساتك هو الذي يضمن أنك ستراعي هذا التغيير بأقل تكلفه ممكنه وبأقل جهد ممكن ...

المرحله الثالثه ، هي مرحله وسيطه بين الأولى والثانيه ، وهي تهتم بالأستخدام الأكفأ effective Usage ، فمثلا دائما ما نفضل أن نرسل المتغيرات العاديه بالقيمه والكائنات اذا لم نكن نريد تغييرها By Reference to const . وتهتم هذه المرحله بالتعريف عن الأمور الغامضه في اللغه مثلا الكلمه المحجوزه mutable (والتي من خلالها في حال كان متغير معرف بها تستطيع تغييرها داخل الـ const member function) .. ولماذا يفضل أن تكون دائما داله البناء explicit ، ولماذا ولماذا ... هذا ما يعرف بالأستخدام الأكفئ للأدوات ... وكما تلاحظ ليس ضروري 100% لكي يعمل البرنامج ولكن بدون تلك الأمور سوف تخسر الكثير من الذاكره وتقوم بعمل الكثير من الأستدعائات لدوال أنت في غني عنها ، أيضا سوف يكون برنامج في Safe Side ولن يقوم بعمل أمور ليست في الحسبان .

تم الحديث بكثره في القسم عن المرحله الأولى ، وتم ذكر بعض النقاط عن الثالثه والتي هي مفيده للغايه في حاله واحده فقط وهي اذا كنت مصمم برنامجك بشكل جيد Good design .

التصميم الجيد للبرنامجك سوف ينتج تبعا له سهوله في الصيانه Maintenance ، سهوله في اضافه المزيد من الكلاسات ، سهوله في اعاده الأستخدام Reuseability ، سهوله في حل المشكله وبمصطلحات المشكله نفسها (وهي ميزه في OOP) .

C++ designer أصعب بكثير جدا من C++ Programming ، لذلك دائما في مجال البرمجيات نجد أن هناك من يطلق عليه senior وهو الذي يساعد المبرمج المبتدئ في البرنامج بيحث يقوم برسم الكلاسات الرئيسيه وكيف تتفاعل مع بعضها البعض وبعدها يقوم المبرمج المبتدئ بالتطبيق لهذا الرسم ..

مقالنا الليله وكبادئه باذنه تعالى سوف يكون مثال عملي للموضوع ، والمقالات القادمه سوف نغوص أكثر في موضوع الـ Object Oriented Analysis And design وأختصارا OOA/D .. فأنت لا تستطيع البرمجه بشكل OO بدون أي يكون هناك تحليل وتصميم مناسب تماما للبرنامج OOA/D .

بما أننا نريد أن يكون الجزء عملي بشكل أكبر حتى يحفز الأعضاء بالبحث في موضوع OOA/D ( لا نريد أن ندخل في Theory مباشره ، قد يُكرٍّه الجميع بما فيهم كاتب الموضوع :) ) . فنأخذ مثال بسيط وهو عباره عن برنامج يقوم بحفظ بيانات طلاب في مكان ما (مصفوفه ، قائمه متصله ، داتا بيز ، ملف ) كما ذكرت المتطلبات قد تتغير .. ويوفر واجهه بسيطه من خلالها نستطيع عمل الأتي :
ادخال بيانات طالب جديد
بحث عن طالب باسمه ، وربما برقمه
معرفه نتيجه الطلاب جميعا
معرفه نتيجه الطلاب الناجحين
معرفه نتيجه الطلاب الراسبين

وحاليا نريد أن نستخدم أبسط الطرق حتى نصل للهدف من الموضوع وهو تقسيم الكلاسات بشكل جيد وكما سنرى فيما بعد في الـ Maintenance لن تحتاج الى تغيير جزء في شفره العميل Interface ، فقط في الـ Implementation .


نبدأ على بركه الله ،


في البدايه أجلب ورقه وقلم ، وحاول أن تتخيل العمليه بشكل مجرد تماما من التفاصيل Thinking Abstract ، وأجب عن السؤال التالي : ما هي الأشياء الأساسيه في البرنامج ؟ (عليك أن تتذكر أن المتطلبات قابله للتغيير) لذلك فكر بشكل عام General وليس مخصص بشئ ما specialization.

نعم بعد قليل من التفكير ستقول هناك "طالب" ، وهناك "مكان" للتخزين ، وهناك "واجهه" تدخل عن طريقها المعلومات . ممتاز ممتاز أنت تبلي حسنا .. دائما عليك في البدايه أن تتخيل البرنامج بأبسط ما يمكن وهو ما يعرف بالـ abstract .. أذا مفهوم الـ Abstraction هو تسهيل وتخيل للعمليه بأبسط شكل ممكن بدون الدخول في الدوال والمؤشرات والمصفوفات وو فقط الوظيفه الأساسيه للكلاس ..

عندما تبدأ بتعريف الكلاس الأول "الطالب" ستقوم بتطبيق ما تعلمته في OOP وعليك بتذكر Access specifies (والتي هي private , public , protected ) وتقوم بتوفير دوال وصول سواء Setter أو Getter . هكذا تكون عرفت "الطالب" ، هكذا تكون عرفت نوع بيانات جديد ليس موجود باللغه New Data Type . ومع "تبسيط" الكلاس سوف ينتج لدينا Abstract Data Type وأختصار ADT .

لماذا قمنا بفصل "الطالب" عن "مكان التخزين" لأن مكان التخزين ليس له علاقه بالطالب ، مكان التخزين يمكن أن يكون مصفوفه Array يمكن أن يكون Linked List ، يمكن أن يكون Data Base .. بالتالي نكون بسطنا الكلاس وأخرجنا الدوال التي لا علاقه لها بالطالب كـ "مكان التخزين" و "وواجهه المستخدم" . وهو ما يعرف بتقسيم مسؤليات كل كائن division of Responsibility .

"واجهه المستخدم" يمكن أن تكون console يمكن أن تكون GUI لا يهم الأن بتاتا هذا الأمر ...

نقوم الأن برسم الكلاسات الأساسيه هنا :
عمليه رسم هذه الكلاسات تختلتف من شخص لأخر ، من مؤسسه لأخرى ، ويمكن أن نعتمد على لغه UML حيث هي لغه تستخدم لوصف الكائنات والعلاقه بينها بمخططات أكثر من واضحه ، وهكذا تكون Standard لأي مبرمج وأخر ..

لكن بما أننا في البدايه ، سنعتمد على أي رسمه (دائره ، مربع لا يهم ) المهم فكره التقسيم تتضح بشكل جيد :




نبدأ الأن بالكلاس الأول : الطالب ..

ماذا يريد الـ Customer هنا ؟
لاحظ الأن قلنا Customer لأننا لن نبرمج برنامج لأنفسنا ، ولكن لـ Customer سوف يعطينا نقود في النهايه (أنت أخي القارئ تمثل الـ Customer ، لا تنسى $$ :) )

كما عليك أن تلاحظ أن "الطريقه" المستخدمه في الـ Software Development Cycle هي التي تحدد متى تبدأ عمليه البرمجه ، بعد أن تجمع جميع المتطلبات كما في الـ Waterfall Model أو أن تقوم في كل مرحله من مراحل التطوير بأخذ المزيد من الـ Requirement بعد أن تري العميل Demo Version أو Prototype وبعدها تأخذ منه الـ FeedBack على ذلك ومنها ستجري التعديلات بناء على ما يريد ، وتكمل هكذا جمع وأنتزاع المتطلبات منه .. بالمناسبه Requirement extracting أمر ليس بهذه السهوله .. خاصه في حال كان الـ customer هو "مبرمج" ... كما حدث معي في أحد المرات لم أستطيع أخذ المتطلبات جميعها الا بعد فتره طويله لأن customer (المبرمج) كان لا يراها ضرويه .. وغير ذلك من الأمور ، ما علينا منها الأن :) .

أخر ملاحظه سوف نتبع الأسلوب الثاني ، وهناك الكثير من الـ Methods المستخدمه في بناء البرمجيات ، وهذا موضوع كبير جدا لن نتطرق له الأن.. لكن كلمه أخيره نموذج الشلال أثبت فشله في أغلب البرمجيات والسبب أنه كما ذكرت أن المتطلبات تتغير وهذا النموذج لا يسمح بالبرمجه الا بعد التحليل والتصميم الكامل للبرنامج !

نعود للطالب مره أخرى ، وبعد الجلوس مع العميل تبين أننا في البرنامج نريد في النهايه أن :
نعرف الأسم الأول والثاني للطالب ودرجته ونتيجته (ناجح أم لا)
نستعلم عن الطالب برقمه أو أسمه الأول والثاني
نخرج نتيجه جميع الطلاب
نخرج نتيجه جميع الطلاب الناجحين
نخرج نتيحه جميع الطلاب الراسبين
نزيد درجات للطالب الفلاني
ننقص درجات من الطالب الفلاني

بالنظر الى المتطلبات سوف ندرك أننا في الكلاس الطالب سوف نحتاج الى المتغيرات :
اسم الطالب والأخير
رقم الطالب
درجه الطالب
نتيجه الطالب

كما تعلم سوف نضع هذه المتغيرات في الجزء private ، حتى نوفر حمايه لها .. وبالتالي سوف نضطر الى توفير دوال Set و Get لتلك المتغيرات ..
داله وضع قيمه لاسم الطالب الأول والأخير
داله وضع قيمه لدرجه الطالب
داله وضع قيمه لنتيجه الطالب
---
داله لارجاع اسم الطالب الأول والأخير
داله لارجاع درجه الطالب
داله لارجاع نتيجه الطالب

هكذا نكون أنهينا دوال Setter & Getter .. ماذا نحتاج بعد ذلك ؟
داله لعرض بيانات الطالب (اسمه ، رقمه ، نتيجته)
داله لانقاص درجه الطالب
داله لزياده درجه الطالب

الأن سوف نقوم بكتابه داله نسميها display لطباعه بيانات الطالب .. وسوف نكتب داله نسميها sub و .. مهلا مهلا مهلا ..

أنت مبرمج سي++ ؟ أليس كذلك
أنت لديك أدوات في اللغه ليست موجوده في جميع اللغات ...
أنت لديك Operator Overloding .. لماذا لا تستفيد منها .
حول الداله Display الى اعاده تعريف الـ Extracting Operator >> .
حول الداله add الى اعاده تعريف المعامل + وبالتالي سوف نجمع الكائن مباشره مع الرقم ..
حول الداله sub الى اعاده تعريف المعامل - وبالتالي سوف نطرح الكائن مباشره مع الرقم ..

سوف تخرج لك شفره جميله .. More Simplicity و More Readability .. ماذا تريد أكثر من هذا :) .


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



تطلع في الملف Student.h وأنظر مليا ...
أعرف أننا قمنا بجعل الدوال Get هي const وذلك من مبدأ الحمايه ، حيث const Member Function لن تغير في قيمه المتغيرات ..

أعرف أننا قمنا بعمل Operator OverLadoing لبعض المعاملات والسبب عمليه الوضوح وسهوله الأستخدام فيما بعد ..

أعرف أننا قمنا بوقع الكلاس بالكامل داخل namespace أسميناها MyRecord وذلك حتى لا يتعارض أسماء الدوال هنا مع دوال أخرى موجوده في كلاسات أخرى قد تستخدمها .. أنظر لجميع كلاسات سي++ القياسيه جميعها موجوده في std namespace .. نحن الان سنضع كل عملنا في MyRecord namespace.. والسبب كما ذكرت الأبتعاد عن مشكله الـ Name collision .

أنتهينا من الملف Student.h ..
دعنا الأن نقوم بتعريف الدوال الموجوده به .. في ملف Student.cpp ..

في داله البناء سوف نعطي المتغيرات قيمه ابتدائيه هنا ..
دوال Set تستقبل قيمه وتضعها في المتغير
دوال Get ترجع قيمه المتغير .
دوال الـ Operator OverLoading تقوم بالعمل المطلوب ..

(اذا كانت هناك مشكله في Operator OverLoading ، راجع الدروس في قسم سي++ ، هو ليس موضوع حديثنا بتاتا ) .

ملف student.cpp :


  1. // Student.cpp
  2.  
  3. #include <iostream>
  4. #include "Student.h"
  5. using namespace std;
  6.  
  7. namespace MyRecord
  8. {
  9. // Constructor
  10. Student :: Student ()
  11. {
  12. firstName = "No";
  13. lastName = "Name";
  14. studentNumber = 0;
  15. studentDegree = 0;
  16. studentResult = false;
  17. }
  18.  
  19. // getter function
  20. string Student :: getFirstName () const {return firstName;}
  21. string Student :: getLastName () const{return lastName; }
  22. int Student :: getStudentDegree() const{return studentDegree; }
  23. int Student :: getStudentNumber() const {return studentNumber;}
  24.  
  25. bool Student :: getStudentResult() {
  26. if ( studentDegree <= FAILER_MARK )
  27. studentResult = false;
  28. else
  29. studentResult = true;
  30.  
  31. return studentResult;
  32. }
  33.  
  34. // setter Function
  35. void Student :: setFirstName ( string fName ) {firstName = fName; }
  36. void Student :: setLastName ( string lName ){lastName = lName; }
  37. void Student :: setStudentDegree ( int degree ){studentDegree = degree;}
  38. void Student :: setStudentNumber ( int number ) { studentNumber = number;}
  39. void Student :: setStudentResult ( bool result) {studentResult = result;}
  40.  
  41. // adding and subtracting degree from student
  42. Student& Student :: operator + ( int degree )
  43. {
  44. studentDegree += degree;
  45. return *this;
  46. }
  47.  
  48. Student& Student :: operator - ( int degree )
  49. {
  50. studentDegree -= degree;
  51. return *this;
  52. }
  53.  
  54. // display function
  55. ostream& operator << (ostream& out , Student& s)
  56. {
  57. out << "nStudent : " << s.getFirstName() << " "
  58. << s.getLastName() << endl
  59. << "Number : " << s.getStudentNumber() << endl
  60. << "Degree : " << s.getStudentDegree() << endl
  61. << "Result : " << (s.getStudentResult() ? "PASS" : "FAIL" )
  62. << endl;
  63.  
  64. return out;
  65. }
  66. }



لاحظ أننا ما زلنا نعمل في MyRecord ، وكل الكلاسات والمتغيرات سوف نضعها هنا في هذه ال Namespace ..


أنتيهنا من كائن الطالب بالكامل ... نبدأ الأن بالكائن الثاني ، مهلا مهلا مهلا .. توقف !!

من قال لك بأن كلاس Student.cpp يعمل ؟
من قال لك بأنه ليست هناك مشاكل فيه ؟

عليك بأختباره أولا ، دائما أختبر الـ Component بعد تطويره وهو ما يزال صغير .. لأننا اذا لم نختبره من الأن صدقوني في حال واجهنا مشكله فيما بعد سوف تصعب للغايه أكتشاف هذا الخطأ ..

لذلك unit Testing بسيط تتأكد من أن الأمور تعمل ، ويكون هذا First Prototype نقدمه للعميل ..

هيا بنا نكتب StudentTest.cpp :

  1. // Test Student class
  2.  
  3. #include <iostream>
  4. #include "Student.h"
  5.  
  6. using namespace std;
  7. using namespace MyRecord;
  8.  
  9. int main (int argv , char** argc)
  10. {
  11. Student std1;
  12. Student std2;
  13.  
  14. std2.setFirstName("Wajdy");
  15. std2.setLastName("Essam");
  16. std2.setStudentNumber(3300);
  17. std2.setStudentDegree(60);
  18.  
  19. std2 = std2 + 3;
  20. cout << std2;
  21.  
  22. cout << endl << endl;
  23.  
  24. cout << std1;
  25.  
  26. return 0;
  27. }


جرب البرنامج ..




واووو ..
الكائن الأول يعمل ، والداله + زادت 3 بشكل صحيح ..
والكائن الثاني يعمل أيضا ، ولكنه فارغ ..

الأن نقوم بالذهاب الى الـ Customer ، نريه هذا العمل البسيط ، هل يريد زياده بيانات في الطالب مثلا رقم تلفونه ومعلومات أخرى .. بالتأكيد لن تكلفك شيء سوى عمل المتغير ودوال Set و Get لذاك المتغير ، وزياده سطر في داله الطباعه .. فقط ، ما أحلاه من تغيير ... أنت سعيد جدا لأنه سهل ولا توجد مشكله ، الـ Customer سوف يكون سعيد أيضا لأن التغيير لن يكلفه الكثير (حتى بعد أن تسلمه البرنامج كامل وطلب هذا التعديل ، النتيجه واحد ) أنا أيضا سعيد لأني سأحصل على حقي من $$ :) .



الكلاس الثاني : "مكان التخزين" ..

لغرض التبسيط في البرنامج سيكون مكان التخزين هو مصفوفه ، ربما تطور البرنامج فيما بعد وتستخدم Vector أو Linked List أو حتى تستخدم driver لكي تتصل بقاعده بيانات .. لا يهم هذا ..

الأن نريد تخزين معلومات الطالب في مصفوفه ، ماذا سنحتاج ؟
بالتأكيد مصفوفه بحجم مناسب .
داله لادخال طالب في المصفوفه
داله لارجاع طالب حسب الأسم الأول والثاني
داله لعرض الطلاب الناجحين
داله لعرض الطلاب الراسبين
داله لعرض الطلاب جميعا

أخر ثلاث دوال لم نضعها في الكلاس student والسبب بالتأكيد أن هذه الدوال لا علاقه لها بالطالب ، هي تتعامل مع مكان التخزين وتقوم بالتعامل معه وليس مع الطالب ..

نبدا في ملف DataBase.h :



أنظر مليا في الكلاس ،
ستجد بأن هناك متغير باسم nextStudentNumber هو الذي يقوم بتحديد رقم الطالب التالي (تلقائيا) من نفسه ..
ستجد بأن المتغير nextSlot هو الذي يقوم بمعرفه المكان التالي في المصفوفه ..

الثابت FIRST_STUDENT_NUMBER هو الذي سيحدد رقم الطالب الأول ، وnextStudentNumber هو الذي سيتحرك من هذه النقطه ..

الدوال البقيه معروفه من الأسم ، تذكر التسميه باسم واضح تعتبر Good Programming Practice تسهل لك ولغيرك العمل ..

لا تنسى أننا ما زلنا نضع كل شيء في MyRecord ..

نشاهد ملف DataBase.cpp وهو تقريبا أهم كلاس هنا في البرنامج ، ركز جيدا !!

  1. // DataBase.cpp
  2.  
  3. #include <iostream>
  4. #include "DataBase.h"
  5.  
  6. using namespace std;
  7.  
  8. namespace MyRecord
  9. {
  10. DataBase :: DataBase ()
  11. {
  12. nextSlot = 0;
  13. nextStudentNumber = FIRST_STUDENT_NUMBER;
  14. }
  15.  
  16. DataBase :: ~DataBase() { }
  17.  
  18. Student& DataBase :: addStudent (string firstName , string lastName , int degree)
  19. {
  20. if ( nextSlot >= MAX_SIZE)
  21. {
  22. cerr << "There is no place in memory ... !";
  23. throw exception();
  24. }
  25.  
  26. Student& st = student[nextSlot++];
  27. st.setFirstName(firstName);
  28. st.setLastName(lastName);
  29. st.setStudentDegree(degree);
  30. st.setStudentNumber(nextStudentNumber++);
  31.  
  32. return st;
  33. }
  34.  
  35. Student& DataBase :: getStudent (int studentNumber )
  36. {
  37. for (int i=0; i<nextSlot; i++)
  38. if ( student[i].getStudentNumber() == studentNumber )
  39. return student[i];
  40.  
  41. cerr << "Cannot find student with number : " << studentNumber << endl;
  42. throw exception();
  43. }
  44.  
  45. Student& DataBase :: getStudent (string firstName , string lastName )
  46. {
  47. for (int i=0; i<nextSlot; i++)
  48. if ( student[i].getFirstName() == firstName &&
  49. student[i].getLastName () == lastName )
  50. return student[i];
  51.  
  52. cerr << "Cannot find student : " << firstName << " " << lastName << endl;
  53. throw exception();
  54. }
  55.  
  56. void DataBase :: displayAll ()
  57. {
  58. for (int i=0; i<nextSlot; i++)
  59. cout << student[i];
  60. }
  61.  
  62. void DataBase :: displayPass ()
  63. {
  64. for (int i=0; i<nextSlot; i++)
  65. if ( student[i].getStudentResult() )
  66. cout << student[i];
  67. }
  68.  
  69. void DataBase :: displayFail ()
  70. {
  71. for (int i=0; i<nextSlot; i++)
  72. if ( ! student[i].getStudentResult() )
  73. cout << student[i];
  74. }
  75. }


داله البناء تعطي الموقع nextSlot الأول في المصفوفه ..
وتهيئ وnextStudentNumber بالرقم الأول الثابت FIRST_STUDENT_NUMBER ..
لماذا ؟
لأنه في حال طلب العميل أن يبدأ ترقيم الطلاب من 1000 ، فقط سوف نغير الثابت ، ولن تغير شيئا أبدا !

يمكن أن نتجاهل ذلك الثابت ، ولكن نضع القيمه 1000 مباشره في nextStudentNumber ، وفي حال طلب العميل التغير نغير ذلك الرقم ، ولكن يفضل الثابت ، الأمور هكذا أكثر ترتيب وأكثر حذرا وأكثر ترقب للتغير في المستقبل ..

لن نحتاج لداله هدم ، لا يوجد شيء نحتاج الى تحريره ..

الأن الداله addStudent سوف تستقبل أسم الطالب الأول والثاني والدرجه .. لكي تضيف الطالب في المصفوفه (أو في مكان التخزين في حال غيرنا الـ Implementation) ..

الداله في البدايه تختبر هل nextSlot وصل الى أقصى حد للمصفوفه ، وفي تلك الحاله سوف نطبع باستخدام الكائن cerr رساله توضح المشكله ونولد exception بحيث يتوقف التنفيذ عند هذه النقطه ، ويكمل في جزء Catch في الداله التي استدعيت هذه الداله ..

الأن تبدأ عليه تخزين الطالب ، سوف نحصل على reference من الموقع التالي في المصفوفه ، ونخزن فيه الأسم والدرجه والرقم .. ونرجع هذا الـ alises .

دوال getStudent سواء باالأسم أم بالرقم ، سوف تبحث من البدايه الى الموقع الحالي ، وترجع الطالب اذا تحقق الشرط ، غير ذلك سوف تقوم بتوليد exception ..

دوال الطباعه ، displayAll سوف تطبع جميع الطلاب (أنظر فائده operator OverLoading هنا ) ، displayPass سوف تطبع الطلاب الناجحين getStudentResult = ناجح true .. أما الداله displayFail سوف تطبع العكس للداله السابقه (!) ..

أنتيهنا من ملف DataBase.cpp ، أعرف أنك لم تنسى الـ Unit testing ، نقوم بكتابه DataBase Test :

  1. // Test DataBase class
  2.  
  3. #include <iostream>
  4. #include "DataBase.h"
  5.  
  6. using namespace std;
  7. using namespace MyRecord;
  8.  
  9. int main (int argc , char** argv )
  10. {
  11. DataBase myDB;
  12.  
  13. Student& s1 = myDB.addStudent("Wajdy","Essam",90);
  14. Student& s2 = myDB.addStudent("Ali","Omer",40);
  15. s2 = s2 + 4;
  16.  
  17. Student& s3 = myDB.getStudent("Wajdy","Essam");
  18.  
  19. cout << "All Student :n";
  20. myDB.displayAll();
  21.  
  22. cout << "nnPass Student :n";
  23. myDB.displayPass();
  24.  
  25. cout << "nnFailer Student :n";
  26. myDB.displayFail();
  27.  
  28. return 0;
  29. }


قمنا بعمل طلاببن وأدخلناهم في الDataBase ، واحد ناجح والثاني راسب :( ، والثالث نسخه من الأول .. وبالتالي المخرج يكون كالتالي :



واوو ، كل هذا الشغل في برنامج بسيط مثل هذا ؟
نعم ، أنت الأن C++ professional وليس C++ newbie :)



تبقى الكلاس الأخير "الواجهه" User Inerface ، وهنا نريد أي واجهه نستطيع من خلالها أدخال المعلومات واٍستخراجها ..

لن نحتاج الى كتابه كلاس كامل في واجهتنا هذه ، فقط جمله while مستمره ، وفيها قائمه تخرج للمستخدم وجمله switch تختار الخيار المناسب ..

ملف UserInterface.cpp :

  1. // UserInterface.cpp
  2.  
  3. #include <iostream>
  4. #include "DataBase.h"
  5.  
  6. using namespace std;
  7. using namespace MyRecord;
  8.  
  9. int menu ();
  10. void addStudent (DataBase& db);
  11. void addDegree (DataBase& db);
  12. void subDegree (DataBase& db);
  13.  
  14. int main (int argc , char** argv)
  15. {
  16. DataBase studentDB;
  17. bool state = true;
  18.  
  19. while ( state )
  20. {
  21. switch ( menu() )
  22. {
  23. case 1:
  24. addStudent(studentDB);
  25. break;
  26.  
  27. case 2:
  28. addDegree(studentDB);
  29. break;
  30.  
  31. case 3:
  32. subDegree(studentDB);
  33. break;
  34.  
  35. case 4:
  36. studentDB.displayAll();
  37. break;
  38.  
  39. case 5:
  40. studentDB.displayPass();
  41. break;
  42.  
  43. case 6:
  44. studentDB.displayFail();
  45. break;
  46.  
  47. case 7 :
  48. state = false;
  49. break;
  50.  
  51. default :
  52. cerr << "Invalid Choice , try Again ...";
  53. break;
  54.  
  55. }
  56. }
  57.  
  58. return 0;
  59. }
  60.  
  61. int menu ()
  62. {
  63. cout << endl << endl << endl;
  64.  
  65. cout << "Student DataBase " << endl
  66. << "-----------------" << endl
  67. << "1) Add Student " << endl
  68. << "2) Add Degree " << endl
  69. << "3) Sub Degree " << endl
  70. << "4) List All Student " << endl
  71. << "5) List All Pass Student " << endl
  72. << "6) List All Fail Student " << endl
  73. << "7) Close DataBase System " << endl
  74. << "t --> ";
  75.  
  76. int selection;
  77. cin >> selection;
  78.  
  79. return selection;
  80. }
  81.  
  82. void addStudent (DataBase& db)
  83. {
  84. string firstName;
  85. string lastName;
  86.  
  87. cout << "Enter First Name : ";
  88. cin >> firstName;
  89.  
  90. cout << "Enter Last Name : ";
  91. cin >> lastName;
  92.  
  93. int degree;
  94. cout << "Enter Degree : ";
  95. cin >> degree;
  96.  
  97. try
  98. {
  99. db.addStudent(firstName,lastName,degree);
  100. }
  101. catch (exception ex)
  102. { cerr << "Unable To Add New Student !n"; }
  103. }
  104.  
  105. void addDegree (DataBase& db)
  106. {
  107. string firstName;
  108. string lastName;
  109.  
  110. cout << "Enter First Name : ";
  111. cin >> firstName;
  112.  
  113. cout << "Enter Last Name : ";
  114. cin >> lastName;
  115.  
  116. int degree;
  117. cout << "Enter Addtion Degree : ";
  118. cin >> degree;
  119.  
  120. try
  121. {
  122. Student& s = db.getStudent(firstName,lastName);
  123. s = s + degree;
  124. }
  125. catch (exception ex)
  126. { cerr << "Unable to Add Degree to Student !n"; }
  127. }
  128.  
  129. void subDegree (DataBase& db)
  130. {
  131. int number;
  132. cout << "Enter Student Number : ";
  133. cin >> number;
  134.  
  135. int degree;
  136. cout << "Enter Subtraction Degree : ";
  137. cin >> degree;
  138.  
  139. try
  140. {
  141. Student& s = db.getStudent(number);
  142. s = s - degree;
  143. }
  144. catch (exception ex)
  145. { cerr << "Unable to Sub Degree From Student !n"; }
  146. }


قمنا بتعريف 3 دوال ، addStudent لادخال بيانات طالب من الكيبورد وبعدها تدخله في المصفوفه .. جمله الأدخال في المصفوفه تكون في try و catch وفي حال حدثت مشكله هناك سوف يتنفذ جزء catch هنا . أما addDegree فتقوم بالحصول على Reference للطالب وبعدها تقوم باجراء الزياده ونفس الأمر مع subDegree ..


لكي يتم تنفيذ البرنامج بشكل صحيح ، قم بوضع الملفات جميعها في مجلد واحد ، واستخدم أمر الترجمه :
g++ *.cpp -o n.exe

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




Congratulation

أنت الأن في الطريق الصحيح لاحتراف سي++ :)

ماذا بعد ذلك ؟ .....
أقرأ :
professional C++ Programmer
كتاب متقدم كما هو واضح من الأسم ،،، للمعلوميه أستفدت منه للغايه في البرنامج ، حيث يوجد برنامج مشابه له في الكتاب ;) .

Thinking in C++
كتاب ممتاز جدا ، يتحدث عن فلسفه سي++ ويقارنها بسي ، مفيد جدا لمبرمجي سي .

وأي كتاب يتحدث عن OOA/D ، سنذكر بعضا منها المره القادمه ان شاء الله ..


حمل جميع الملفات ، بالأضافه الى مجلد test يحتوي على ملفات الأختبار :
Here

الى اللقاء .

إسم الكاتب تاريخ الإضافة التقييم / المقيمين زيارات الدرس
romansy 19/02/2009 10 / 1 2130

الأكثر زيارة

 دليل تنصيب اطار عمل Qt ، حزمة MinGW ، بيئة التطوير QDevelop
الزيارات 4284 دليل تنصيب اطار عمل Qt ، حزمة MinGW ، بيئة التطوير QDevelop
 اعداد وتنصيب Qt
الزيارات 4072 اعداد وتنصيب Qt
 التطوير السريع للتطبيقات Rapid Application Development
الزيارات 3764 التطوير السريع للتطبيقات Rapid Application Development
 دليل تنصيب اطار عمل Qt ، حزمة MinGW ، بيئة التطوير Eclipse
الزيارات 3747 دليل تنصيب اطار عمل Qt ، حزمة MinGW ، بيئة التطوير Eclipse
 C++ In a Nutshell
الزيارات 3155 C++ In a Nutshell
 

الأكثر تصويتـا

 اعداد وتنصيب Qt
نتيجة التصويت 41 من 6 شخص اعداد وتنصيب Qt
 الدرس الاول : كتابة اول برنامج
نتيجة التصويت 41 من 6 شخص الدرس الاول : كتابة اول برنامج
 تخطيط البرامج Program Layout
نتيجة التصويت 40 من 6 شخص تخطيط البرامج Program Layout
 دوال المستوى العالي لبرمجة تطبيقات متعددة المسالك
نتيجة التصويت 30 من 3 شخص دوال المستوى العالي لبرمجة تطبيقات متعددة المسالك
 التطوير السريع للتطبيقات Rapid Application Development
نتيجة التصويت 30 من 5 شخص التطوير السريع للتطبيقات Rapid Application Development
 
 

سكربت story-script v1 برمجة bwady.com تطوير SudaNix