C++ 3
فهرس انمحتىٌاث مقدمة إلى البرمجة البداٌة مع البرمجة لغة البرمجة لمحة تارٌخٌّة عن C++ لمن هذا الكتاب ؟ كٌف أقرأ هذا الكتاب ؟ فصول الكتاب التعامل مع المترجم visual c++ 6.0
القسم األول
الفصل األول :بنٌة البرنامج فً لغة الـ C++
9 10 10 11 11 11 23 14 17
تنسٌق الكتابة
18
التعلٌقات
19
تمارٌن
19
الفصل الثانً :المتغ ٌّرات ( ( Variables
20
حساسٌة اللغة لحالة األحرف
21
أنواع البٌانات )(Data types
21
مقدّمة إلى السبلسل ) ( strings
24
تمارٌن
25
الفصل الثالث :اإلدخال و اإلخراج ) ( Input and Output
26
تعلٌمة اإلخراج )(cout
26
تعلٌمة اإلدخال )(input cin
28
بعض الرموز الخاصة
28
تمارٌن
29
الفصل الرابع :الثوابت ()Constants
30
الفصل الخامس :المعامالت )(Operators
31
اإلسناد )=(
31
المعامبلت الرٌاضٌّة ) ( + , - , * , / , %
31
معامبلت اإلسناد المركبة ) =| ( += , -= , *= , /= , %= , &= , ^= ,
32
معامبلت الزٌادة والنقصان )(++ , --
32
معامبلت المقارنة ) => ( == , != , < , > , <= ,
32
المعامبلت المنطق ٌّة ) || ( ! , && ,
33
المعامل الشرطً ) ؟ (
33
معامل تحوٌل البٌانات
34
4
المعامل )(sizeof
34
أولوٌات تنفٌذ المعامبلت
34
تمارٌن
36
الفصل السادس :بنى التحكم ()Control Structures
37
بنٌة الشرط condition structure
37
بنى التكرار loops or repetition structures
39
التعلٌمة break
42
التعلٌمة continue
42
التعلٌمة goto
43
التعلٌمة switch
43
الحلقات المتداخلة nested loops
46
تمارٌن محلولة
48
تمارٌن
56
الفصل السابع :التوابع ()Functions
58
التوابع التً ال تعٌد قٌمة ) استخدام الكلمة ( void
60
تمر ٌر الوسطاء بالقٌمة وبالمرجع )العنوان(
61
المدى Scope
63
المتغٌرات الشاملة Global variablesو المتغٌرات الموضعٌة Local variables
63
المتغٌرات الثابتة static
64
تعٌٌن القٌمة االفتراضٌة للوسطاء
64
إعادة تحمٌل التوابع functions overloading
65
التعرٌف المبدبً للتوابع functions prototype
65
الفصل الثامن :التعاودٌة ()Recursion
67
تمارٌن محلولة
72
تمارٌن
86
القسم الثانً
الفصل التاسع :المصفوفات ()Arrays
78
التعامل مع المصفوفات
79
المصفوفات المتعددة األبعاد
80
المصفوفات كمعامبلت )وسطاء( للتوابع
82
األعداد العشوابٌة
83
تمارٌن محلولة
85
تمارٌن
90 5
الفصل العاشر :سالسل الرموز ()Strings of Characters التعامل مع السبلسل الفصل الحادي عشر :المؤشرات ()pointers
92 92 95
معامل العنوان ) & (
95
معامل المرجع ) * (
95
التصرٌح عن المإ ّ شرات
:7
المإ ّ شرات والمصفوفات
:8
تبدبة المإ ّ شرات
:9
مصفوفة المإ ّ شرات
:9
العملٌات الحسابٌة على المإ ّ شرات
99
شرات على المإ ّ المإ ّ شرات
100
المإ ّ شرات الخالٌة void pointers
100
المإ ّ شرات على التوابع
101
الفصل الثانً عشر :الذاكرة الدٌنامٌكٌة ()Dynamic Memory
103
المعامل new
103
المعامل delete
104
الفصل الثالث عشر :التراكٌب ()Structures
105
تراكٌب المعطٌات
105
مصفوفة التراكٌب
107
التراكٌب و المإ ّ شرات
108
التراكٌب المتداخلة
109
الفصل الرابع عشر :األنواع المعرفة من قبل المستخدم
113
تعرٌف أنواع خاصّة ) ( typedef
113
الوحدات ) ( Unions
113
المر ّقمات ) Enumerations ( enum
114
الفصل الخامس عشر :اإلدخال و اإلخراج فً الملفات
114
فتح ملف
115
إغبلق ملف
116
الملفات النصٌّة
116
التحقق من الحالة
117
مإ ّ شرا التدفق ) putو ( get
117
الفصل السادس عشر :معالجة االستثناءات ( ) Exceptions handling
119 6
القسم الثالث
التوجه ()OOP الفصل السابع عشر :البرمجة كائن ٌّة ّ
122
مقدّمة
122
معرّ فات الوصول Access modifieres
123
معامل المدى ::
125
التوابع األعضاء inline
125
المشٌّدات Constructors
128
الهادمات Destructors
129
إعادة تحمٌل المشٌّدات Overloading Constructors
129
المإ ّ شرات على الصفوف Pointers to classes
132
الكلمة المفتاحٌّة this
133
الصفوف المعرّ فة باستخدام الكلمة المحجوزة struct
135
إعادة تحمٌل المعامبلت Overloading operators
135
األعضاء الثابتة من النوع static
138
التوجه ()OOP principles الفصل الثامن عشر :مبادئ البرمجة كائن ٌّة ّ
140
مبدأ التغلٌف Encapsulation
140
التوابع friendالكلمة المفتاحٌّة ) ( friend
142
الصفوف من النوع friend
143
الوراثة بٌن الصفوف Inheritance between classes
144
الوراثة المتعددة Multiple inheritance
147
تعدد األشكال Polymorphism
148
المإ ّ شرات على الصفّ األساسً Pointers to base class
148
األعضاء من النوع virtual
149
الصفوف األساسٌّة المجردة Abstract base classes
152
الفصل التاسع عشر :القوالب ()Templates
155
تابع القوالب
155
صفّ القوالب
157
تخصٌص القالب Template specialization
158
الفصل العشرون :فضاءات األسماء ()Namespaces
061
التعلٌمة using namespace
272
الفضاء std
273
حلول التمارٌن غٌر المحلولة
061
7
املقدّمة:
الحمد هلل ربّ العالمٌن الرحمن الرحٌم مالك ٌوم الدٌن ,والصبلة والسبلم على س ٌّد األوّ لٌن واآلخرٌن مح ّمد النبًّ األمٌن وعلى آله وصحبه ال ُغرِّ المٌامٌن ومن اهتدى بهدٌهم واستنَّ بسنتهم أجمعٌن. قال هللا تعالى" :1وقل ربِّ ِزدنً علما" .قال ابنُ كثٌر فً تفسٌره" :أي :زدنً منك علما". قال ابن ُع ٌَ ٌْ َن َة رحمه هللا" :ولم ٌزل رسول هللا صلى هللا علٌه وسلم فً زٌادة ] من العلم [ ح ّتى تو ّفاه هللا ع ّز وج ّل". وعن أبً هرٌرة ,رضً هللا عنه ,أنّ رسول هللا ,صلى هللا علٌه وسلم ,قال" :ومن سلك طرٌقا ٌلتمس فٌه علما, س ّهل هللا له به طرٌقا إلى الجنة". ٌ ملعونة ,ملعونٌ ما فٌها ,إال ذكر هللا تعالى ,وما وعنه قال :سمعت رسول هللا ,صلى هللا علٌه وسلمٌ ,قول" :الدنٌا 2 وااله ,وعالما ,أو متعلما". وعن أنس ,رضً هللا عنه قال :قال رسول هللا ,صلى هللا علٌه وسلم" :من خرج فً طلب العلم ,فهو فً سبٌل 3 هللا ح ّتى ٌرجع". خٌر وعن أبً سعٌ ٍد الخدري4 ,رضً هللا عنه ,عن رسول هللا ,صلى هللا علٌه وسلم ,قال" :لن ٌشبع مإمنٌ من ٍ ح ّتى ٌكون منتهاه الجنة". وعن أبً أمامة ,رضً هللا عنه ,أنّ رسول هللا ,صلى هللا علٌه وسلم ,قال" :فضل العالم على العابد كفضلً على أدناكم ث ّم قال رسول هللا ,صلى هللا علٌه وسلم :إن هللا ومبلبكته وأهل السموات واألرض حتى النملة فً 5 جحرها وحتى الحوت لٌصلون على معلمً الناس الخٌر". علم فكتمه ,ألجم ٌوم وعن أبً هرٌرة, رضً هللا عنه ,قال :قال رسول هللا صلى هللا علٌه وسلم" :من سبل عن ٍ 6 ار". ن القٌامة بلجام من ٍ ٍ إنّ ما تق ّدم من اآلٌات واألحادٌث إ ّنما ٌ ّدل على فضل العلم و ّ صل األجر طبلبه فً الدنٌا واآلخرة ولكً ُتح ّ العظٌم من هللا تعالى علٌك أن تعلم أنّ ن ٌّتك فً طلب العلم مه ّمة فقد روى إماما المح ِّدثٌن البخاريّ ومسلم رضً حفص عمر بن الخطاب هللا عنهما فً صحٌحٌهما -اللذٌن هما أص ّح الكتب المص ّنفة -عن أمٌر المإمنٌن أبً ٍ ئ ما رضً هللا عنه ,قال" :سمعت رسول هللا صلى هللا علٌه وسلم ٌقول :إ ّنما األعمال بالن ٌّات ,وإ ّنما لك ّل امر ٍ نوى فمن كانت هجرته إلى هللا ورسوله فهجرته إلى هللا ورسوله ,ومن كانت هجرته لدنٌا ٌصٌبها ,أو امرأ ٍة 7 ٌن ِك ُحها فهجرته إلى ما هاجر إلٌه". إ ّنما ُجعِل هذا الكتابُ لٌكون مساعدا للذٌن ٌو ّدون تعلّم شًء من علوم البرمجة )برمجة الحاسب( وفً محاول ٍة ك أح ٌد بإهمٌته للبشرٌة جمعاء ولؤل ّمة اإلسبلم ٌّة على وجه لزٌادة الكتب العرب ٌّة التً تهت ّم بهذا العلم الذي ال ٌش ُّ ْ ُ ُ الخصوص تلك األمّة التً خاطبها هللا تعالى فقالُ " :ك ْن ُت ْم َخٌ َْر أ َّم ٍة أ ْخ ِر َج ْ ُون ِب ْال َمعْ رُوفِ َو َت ْن َه ْو َن َع ِن اس َتؤ ُمر َ ت لِل َّن ِ 8 ان َخٌْرا لَ ُه ْم". اهلل َولَ ْو آ َم َن أَهْ ُل ْال ِك َتا ِ ب لَ َك َ ون ِب َّ ِ ْال ُم ْن َك ِر َو ُت ْإ ِم ُن َ سابلٌن المولى ّ عز وج ّل أن تعود هذه األ ّمة إلى عهدها قابدة ورابدة فً كل المجاالت ومشكاة للنور ومنبعا للفكر العذب الصافً. تعفو عمّا كان من الخطؤ أو إنّ الذ ٌْ ِن كتبا هذا الكتاب هما من البشر لذلك نرجو منك أٌُّها القار ُ ئ الفاض ُل أن َ ُ ٌ النسٌان وأن تذكر أنّ الكمال هلل وحده .أخٌرا هذا الكتاب لٌس مجانٌّا بالكامل وثمنه دعوة بالغٌب لنا وللمسلمٌن فبل تنسونا من دعابكم. 1سورة طه اآلٌة 114 : ٌ 2رواه الترمذي وقال :حدٌث حسنٌ .قوله وما وااله أي :طاعة هللا. ٌ حدٌث حسنٌ . 3رواه الترمذي وقال: ٌ حدٌث حسنٌ . 4رواه الترمذي وقال: ٌ 5رواه الترمذي وقال :حدٌث حسنٌ . ٌ 6رواه أبو داود والترمذي وقال :حدٌث حسنٌ . 7 ٌ متفق على صحته. 8سورة آل عمران اآلٌة 221 :
8
إهداء محمد صلى اهلل عليو وسلم. األول ّ إلى المعلّم ّ عّا . إلى والدينا األ ّ إلى أصحاب الفضل علينا من إخواننا ومعلّمينا الفضال . كل المسلمين. إلى ّ إلى من كان السبب في إخراج ىذا الكتاب
المؤلفان السبت 81ذي القعدة سنة 8341هجريّة األول سنة 1188ميالديّة 81تشرين ّ
9
مق ّدمة إلى البرمجة تحت ّل علوم الحاسب اإللكترونًّ فً أٌامنا هذه مكانة عالٌة بٌن العلوم وهً ترتبط بشكل وثٌق ج ّدا مع ك ّل العلوم األخرى بدء بالعلوم الرٌاض ٌّة والفٌزٌاب ٌّة مرورا بعلوم اللغات والعلوم الطب ٌّة وغٌرها. وم ّما هو معلوم عند الناس أنّ الحاسبات تإ ّدي العدٌد من الوظابف المه ّمة فً حٌاتنا الٌومٌة بسرعة وكفاءة عالٌتٌن وبدقة كبٌرة فً النتابج األمر الذي ساعد العلماء على اختراع الكثٌر من اإلبداعات العلمٌة بسرعة كبٌرة تفوق تصوّ رات الكثٌرٌن من البشر ابتداء باآلالت المٌكانٌكٌة كالسٌارات إلى عالم اإلنترنت الملًء بالمفاجآت وصوال إلى القمر حٌث استطاع البشر الوصول إلٌه بإذن هللا تعالى ث ّم بما أبدعته عقول العلماء وبمساعدة هذه الحاسبات. ّإال أنّ الحاسب ال ٌستطٌع أن ٌفعل أي شًء مالم ٌقم اإلنسان بتعلٌمه وتدرٌبه على القٌام به هذا األمر من خبلل صٌصا لٌرافقك عزٌزي القارئ فً رحلة- برمجة الحاسب على القٌام بما نرٌده أن ٌقوم به وهذا الكتاب ُ ص ِنع ِخ ّ نرجو من هللا أن تكون ممتعة بالنسبة لك– فً رحاب إحدى أه ّم وأقوى لغات البرمجة لتتم ّكن بعدها من قٌادة حاسبك وجعلِه ٌفعل كل األشٌاء التً ترٌدها منه. ٌشبه هذا األمر الطرٌقة التً ٌ ّتبعها الناس فً تربٌة وتعلٌم أبنابهم حٌث ٌُول ُو َنهم الحبّ والرحمة وٌحاولون جاهدٌن أن ٌجعلوا من أوالدهم أفضل ما ٌمكن ,وما نرٌده منك فً هذه الرحلة أن تعزم على أن تقرأ هذا الكتاب فالصبر كامبل وأن تتحلى بالصبر قال هللا تعالى " :واستعٌنوا بالصبر والصبلة وإ ّنها لكبٌرة إال على الخاشعٌن", َ الصبر. قد ٌبدو األمر صعبا فً أوّ له ولك ّنه سٌسهل شٌبا فشٌبا مع تق ّدمك فً صفحات هذا الكتاب وتمرّ نك على ما فٌه من التمارٌن واألسبلة وال تكتفِ بذلك بل اكتب كل ما ٌخطر ببالك من برامج وإن لم تتم ّكن من ذلك بسهولة ,و حاول أن تح ّل ك ّل المشاكل التً تواجهها باستخدام البرمجة لٌتث ّنى لك ما ترٌد ,وتذ ّكر دابما ما قاله أجدادنا الحكماء" :إهمال ساعة ٌفسد رٌاضة دهر" فإ ٌّاك واإلهمال وواصل العمل بج ّد فمن ج ّد وجد ومن سار على الدرب وصل ,ولكً تكون على الدرب علٌك أوّ ال أن تعرف الدرب وهذا ال ٌكون ّإال بالتخطٌط وتحدٌد األهداف ث ّم األسباب ث ّم تضع الخطة وتبدأ بتنفٌذها وتذ ّكر هدفك دوما –الغاٌة األسما لكل مسلم إرضاء هللا عز وجل– واعمل له ك ّل ساعة. أخٌرا أقول لكِ " :اعمل لدنٌاك كؤ ّنك تعٌش أبدا واعمل آلخرتك كؤ ّنك تموت غدا".
:
البداٌة مع البرمجة نقصد بالبرمجة صناعة البرامج ولٌس شرطا أن تكون برامجا تعمل فقط على الحاسبات أو على اآلالت اإللكترونٌة .البرامج هً مجموعة من التعابٌر المنطقٌّة والرٌاض ٌّة الخاصة المرتبطة مع بعضها لتكوّ ن حلوال لمشاكل معٌنة. ولكً نكتب برنامجا ما علٌنا أن نقوم بخطوات مح ّددة قبل ذلك وهذه الخطوات تبدأ أوّ ال بتحلٌل المشكلة المعطاة إلى مشاكل أبسط ث ّم نقوم بوضع خطوات الحل وذلك وفق ترتٌب مع ٌّن ٌبلبم التحلٌل الذي حصلنا علٌه وهذا الترتٌب لخطوات الحل ٌدعى بالخوارزمٌة ,ث ّم كتابة البرنامج بلغة البرمجة. الخوارزمٌة :هً خطوات منطق ٌّة مر ّتبة ترتٌبا صحٌحا لح ّل مشكلة مع ٌّنة. ال ب ّد فً كل برنامج من مرحلتً التحلٌل وكتابة الخوارزمٌة بعد ذلك ٌؤتً دور الحاسب .حٌث ٌتبقّى أن تقوم بترجمة الخوارزمٌة التً صغتها إلى برنامج مكتوب بإحدى لغات البرمجة ث ّم ٌقوم الحاسب بعمله لٌعطٌك البرنامج الذي قمت بكتابه. مثبل ّ لنفترض أ ّننا نرٌد أن نقوم بحساب مساحة مستطٌل. ّأوالا :لنحلّل هذه المشكلة ما هو المستطٌل و كٌف نحسب مساحته ؟ المسطٌل هو شكل هندسً له أربعة أضبلع اثنان منها ٌمثبلن الطول واالثنان اآلخران ٌمثبلن العرض أ ّما مساحته فهً تنتج من ضرب الطول بالعرض. الخوارزمٌة: -1اقرأ الطول ث ّم العرض -2اضرب الطول بالعرض -3أعطنً الناتج هذه الخطوات ّ تمثل خوارزم ٌّة لحل مشكلتنا السابقة .سنعتمد فً هذا الكتاب على كتابة الخوارزمٌات بنفس صصة فً هذا المجال أ ّما هذا الكتاب الطرٌقة السابقة .ولن نكثر من الشرح حول الخوارزم ٌّات فهناك كتب متخ ّ فهو ٌناقش البرمجة وبعض البرامج وما ٌه ّمنا هو توضٌح الفكرة من الخوارزمٌات فقط ولن نحتاج إلٌها كثٌرا خبلل هذه الرحلة وٌمكنك التو ّسع فً ذلك المجال بقراءة بعض الكتب المختصة .اآلن بعد أن قمنا بوضع الخوارزم ٌّة بقٌت المرحلة األخٌرة لكتابة البرنامج أال وهً ترجمتها إلى لغة برمجة ٌعرفها الحاسب. لغة البرمجة ٌواجه المبرمجون المشكلة ذاتها التً ٌواجهها المسافرون إلى بلدان أجنب ٌّة وهً مشكلة اختبلف لغة التخاطب بٌن المسافر والبلد الذي سافر إلٌه فكان من المناسب إٌجاد ح ّل لهذه المشكلة وهو الٌوم اتقان اللغة األكثر شهرة مثل اللغة اإلنكلٌز ٌّة مثبل فمعظم الناس ٌستطٌعون التح ّدث بهذه اللغة ,وكذلك األمر عند المبرمجٌن ت ّم إٌجاد صة للتخاطب بٌن البشر)المبرمجٌن( والحاسب والتً تعرف بلغات البرمجة programming لغات خا ّ languagesوهذه اللغات صنعت لهذا الغرض ولن نطٌل الكبلم حول هذا الموضوع فالكبلم فٌه طوٌل ولٌس له أهم ٌّة كبٌرة فً تعلّم البرمجة وتستطٌع عزٌزي القارئ الحصول على المعلومات الكاملة حول هذا الموضوع من خبلل اإلنترنت ففٌه الكثٌر م ّما ٌجب علٌك أن تتعلّمه أ ّما ما ٌه ّمنا هنا هو أنّ ما ٌكتب باستخدام لغة البرمجة ٌسمى شٌفرة. لكً ٌستطٌع الحاسب معرفة هذه اللغة ت ّم تصنٌع برامج أخرى س ّمٌت مترجمات compilersتقوم هذه المترجمات بترجمة الشٌفرة التً تكتب بلغة البرمجة إلى لغة أخرى هً لغة اآللة إذ أنّ الحاسب ٌمتلك لغة صة حٌث ّ ٌمثل كل البٌانات والمعلومات فٌه على شكل سبلسل من األرقام الثناب ٌّة ) 0و (1ما ٌجعل خا ّ التخاطب معه بلغته أمرا فً غاٌة الصعوبة والتعقٌد.
21
لمحة تارٌخ ٌّة عن C++ طوّ رت C++من لغة Cالتً طوّ رت بدورها من لغتٌن سابقتٌن هما BCPLو . B قام مارتٌن رٌكارد Martin Richardsعام 2:78م بتطوٌر BCPLكلغة لكتابة أنظمة التشغٌل والتطبٌقات و المترجمات. وأضاف كِن ثومبثون Ken Thompsonالعدٌد من المٌزات الجدٌدة إلى لغته Bالتً تشبه BCPLإلى ح ّد كبٌر واستخدمها فً إنتاج النسخ األولى من نظام التشغٌل Unixالشهٌر وذلك فً مختبرات Bellعام 2:81م باستخدام الحاسب المعروف بـ DEC DPD-7كلتا اللغتٌن كانتا عدٌمتً األنواع فً البداٌة. طوّ ر دٌنِس رٌتشً Dennis Retchieلغة Cمن لغة Bفً مختبرات Bellباستخدام الحاسب DEC DPD- 11عام 2:83م. حٌث استخدمت Cالعدٌد من األفكار الموجودة فً اللغتٌن Bو BCPLو أضافت إلٌهما أنواع البٌانات وبعض المٌزات األخرى. ومن هذه اللغة التً تل ّقت العدٌد من التعدٌبلت والتطوٌرات ح ّتى نالت درجة القٌاسٌة العالمٌة ) ISO(International Standards Organaizatoionت ّم تطوٌر لغة C++فً مختبرات Bellمن خبلل Bjarne Stroustrupفً مطلع الث ّمانٌنات. زوّ دت C++بمجموعة من المزاٌا ّإال أنّ أه ّمها كان دعمها لمبادئ البرمجة كابن ٌّة التوجه OOP(Object- )Oriented Programming لمن هذا الكتاب ؟ هذا الكتاب لك ّل من ٌرٌد أن ٌتعلّم البرمجة وال ٌفترض هذا الكتاب وجود أيّ معرفة لدى القارئ لذلك لٌس مه ّما إن كانت هذه أوّ ل مرّ ة تقرأ فٌها كتابا فً هذا المجال أو إن كانت المرّ ة األولى التً تقرّ ر فٌها تعلّم البرمجة ,وكذلك لؤلشخاص الذٌن ٌو ّدون االنتقال من لغات أخرى إلى هذه اللغة ٌمكن أن ٌق ّدم هذا الكتاب المبادئ األساس ٌّة للبرمجة باستخدام لغة C++ولكنّ هذا الكتاب ال ٌعطً لؤلشخاص المتق ّدمٌن فً البرمجة سوى مراجعة لبعض معلوماتهم السابقة وقد ٌضٌف بعض األفكار البسٌطة إن لم ٌكونوا قرإوها من قبل. كٌف أقرأ هذا الكتاب ؟ إن كنت مبتدبا ولم ٌسبق لك أن كتبت برنامجا من قبل فعلٌك أن تبدأ من حٌث أنت أ ّما إن كان لدٌك تصوّ ر كا ٍ ف عن البرمجة بهذه اللغة فٌمكنك أن تختار الموضوع الذي تو ّد البدء منه فالكتاب مق ّسم إلى ثبلثة أقسام ربٌس ٌّة القسم األول و الذي ٌحتوي على المبادئ األساسٌة لكل المبتدبٌن فً البرمجة والقسم الثانً الذي ٌحتوي على مواضٌع أكثر تقدّما كالمصفوفات والذاكرة الدٌنامٌك ٌّة والمإ ّ شرات أ ّما القسم الثالث فقد ت ّم تخصٌصه للحدٌث عن البرمجة الكابن ٌّة التوجه وهً مرحلة متق ّدمة بعض الشًء لذلك إن لم تتقن الفصول التً تسبقها فستواجه العدٌد من المشاكل.
22
فصول الكتاب األول :بنٌة البرنامج فً لغة C++ الفصل ّ نتح ّدث فً هذا الفصل عن البنٌة األساس ٌّة للبرنامج وفق قواعد اللغة ونتناول أه ّم العناصر المش ّكلة للبرنامج ونشرح ك ّل واحدة منها من خبلل البرنامج األوّ ل لنا فً هذا الكتاب.
الفصل الثانً :المتغ ٌّرات نطرح فً هذا الفصل فكرة المتغٌّرات التً تشبه خبلٌا الذاكرة فً دماغ اإلنسان فهً خبلٌا فً ذاكرة الحاسب ٌستخدمها الحاسب لتخزٌن القٌم التً ٌحتاجها أثناء تنفٌذ البرنامج وسنناقش كٌفٌة التعامل معها أٌضا. الفصل الثالث :اإلدخال و اإلخراج هذا الفصل هو بداٌتك لكً تكون قادرا على التواصل مع الحاسب بشكل مباشر حٌث ستتم ّكن من الطباعة على الشاشة و القراءة من لوحة المفاتٌح وهذا هو التخاطب الذي نبحث عنه بٌن المبرمج والحاسب. الفصل الرابع :الثوابت فً هذا الفصل سنشرح فكرة استخدام الثوابت و الفرق بٌنها و بٌن المتغٌّرات. الفصل الخامس :المعامالت صة تقوم بوظابف من نقصد بها الرموز التً تعنً للحاسب عمل ٌّات معٌّنة إما رٌاض ٌّة أو منطق ٌّة أو عمل ٌّات خا ّ أنواع أخرى والمعامبلت ضرور ٌّة ج ّدا وال ٌخلو برنامج منها أبدا لذلك ننصحك بالتم ّعن أثناء قراءتها و التمرّ ن علٌها بشكل ج ٌّد. الفصل السادس :بنى التحكم صة تقوم بوظابف معٌنة منها ما ٌدعى ببنى الشرط و منها ما نق ّدم هنا أه ّم البنى البرمج ٌّة وهً تعلٌمات خا ّ ٌدعى ببنى التكرار وهً أنواع نتع ّرف علٌها فً حٌنها ث ّم نشرح فٌه بعض الكلمات المستخدمة مع هذه البنى لمساعدتنا فً إدارة برامجنا بشكل كامل. الفصل السابع :التوابع تمثل التوابع البنٌة الربٌس ٌّة للبرنامج ولها فوابد أخرى حٌث تس ّهل التوابع كتابة البرامج وتق ّسم البرامج إلى أقسام ّ ّ منظمة واضحة للمبرمج ولقارئ الشٌفرة.
الفصل الثامن :التعاودٌة أسلوب خاصّ لكتابة التوابع ّ ٌتمثل بتكرار التابع عددا منتهٌا من المرّ ات دون استخدام بنى التكرار وهذا الفصل من أكثر الفصول صعوبة وفٌه من المتعة الشًء الكثٌر وتجدر اإلشارة إلى أنّ هذا الفصل غٌر مه ّم كثٌرا أل ّنه ٌستغنى عنه باستخدام البنى التكرارٌة. الفصل التاسع :المصفوفات بنى معطٌات تسهّل التعامل مع البٌانات التً لها نفس النوع كالبحث والترتٌب والتخزٌن الفصل العاشر :سالسل الرموز نناقش هنا كٌفٌة التعامل مع النصوص حٌث ٌت ّم تمثٌل الكلمات والنصوص بسبلسل من األحرف )الرموز(. 23
الفصل الحادي عشر :المؤ ّ شرات تعتبر المإ ّ شرات من أقوى مٌزات لغة الـ C++حٌث تسمح لنا بالتعامل مع الذاكرة مباشرة وتم ّكننا من إنشاء بنى معطٌات دٌنامٌكٌة .أحٌانا تكون المإ ّ شرات صعبة الفهم ولكنّ مفهومها بسٌط وٌصبح التعامل معها سهبل كلّما زاد التمرّ ن وكتابة األكواد المتعلقة بها. الفصل الثانً عشر :الذاكرة الدٌنامٌكٌة شرات حٌث ٌت ّم حجز الذاكرة أثناء تنفٌذ البرنامج باستخدام المإ ّ مفهوم الذاكرة الدٌنامٌك ٌّة مرتبط جدّا بالمإ ّ شرات الفصل الثالث عشر :التراكٌب هً بنى معطٌات خاصّة تسمح لنا بجمع ع ّدة أنواع من المعطٌات تحت نوع واحد وهً مهمّة فً قواعد البٌانات المعرفة من قبل المستخدم الفصل الرابع عشر :األنواع ّ نعرّ ف هنا أنواع بٌانات جدٌدة غٌر موجودة باالعتماد على أنواع موجودة ومعرّ فة مسبقا. الفصل الخامس عشر :اإلدخال و اإلخراج فً الملفات نتعلم هنا كٌفٌة التعامل مع المل ّفات سواء قراءة محتوٌاتها أو الكتابة علٌها أو البحث فٌها. الفصل السادس عشر :معالجة االستثناءات هذا الفصل هو عبارة عن إضافة جدٌدة إلى لغة C++نتع ّرف من خبلله على طرٌقة عمل ٌّة فً منع تدمٌر البرنامج الناجم عن أخطاء مع ٌّنة فً العمل ٌّات داخل البرنامج كؤن ٌدخل المستخدم حرفا أو اسما بدال من أن ٌدخل رقما .مثل هذه األخطاء قد تتسبب بتوقف البرنامج وتدمٌره لذلك سٌكون من األفضل التخلّص منها بطرٌقة آمنة. الفصل السابع عشر :مقدمة إلى البرمجة كائنٌة التوجه ٌعتبر هذا الفصل مدخبل إلى الصّفوف والكابنات وٌق ّدم بعض المفاهٌم التً تخصّ هذا النمط من البرمجة صفوف )األنواع( الجدٌدة وأشٌاء أخرى تتعلّق بها. وٌتح ّدث عن أسلوب بناء ال ّ الفصل الثامن عشر :مبادئ البرمجة كائنٌة التوجه نتعرّ ض فً هذا الفصل إلى المبادئ الثبلث للبرمجة كابن ٌّة التوجّ ه ونشرحها بشكل سهل و مختصر ونق ّدم بعض األمثلة علٌها فً محاولة لتقدٌم فكرة بسٌطة عن هذا النمط من البرمجة وال ٌعتبر هذا الكتاب كافٌا فً هذا المجال. الفصل التاسع عشر :القوالب أسلوب قويّ ج ّدا للتعامل مع الصفوف والتوابع واختصار الوقت والجهد األمر الذي ستتعرّ ف علٌه عندما تنهً آخر صفحة من صفحات البرمجة الكابن ٌّة. الفصل العشرون :فضاءات األسماء مكتبات قٌاس ٌّة موجودة فً لغة C++القٌاس ٌّة تحتوي على الكثٌر من المزاٌا و التوابع التً تو ّفر علٌك الوقت و الجهد فهً تحوي المبات من التوابع الجاهزة والتً ستحتاجها فً ك ّل برامجك .سن ّتعلم بسرعة كٌف ٌمكننا أن صة بنا. نصنع فضاءات األسماء الخا ّ
24
التعامل مع المترجم visual c++ 6.0 نقوم بفتح البرنامج بعد تنصٌبه على الحاسب فتظهر النافذة التالٌة
نختار Newمن القائمة Fileث ّم نختار التبوٌب Filesث ّم نختار C++ Source Fileث ّم نحدد اسم الملف ومكان الحفظ 9ث ّم نضغط الزر OK
9
أحٌانا ٌجب تغٌٌر مكان الحفظ عند العمل على Windows 7
25
نكتب البرنامج فً المحرّ ر الذي ٌظهر ونضغط الزر الشكل
نضغط الزر
) (compileأو ctrl+f7لترجمة الشٌفرة كما فً
أو ctrl+f5لتنفٌذ البرنامج كما فً الصورة
26
القسم األول ضل ما ال َف ُ در ُك ِّل َوقَ ُ فَه ُفز بِعِم ٍِ
إِّل ِأل ِ َهل العِم ِ إَِّه ُُ ُِ ِ ِ ام ِر ٍئ ما كاَن ُُيسنُهُ َول تَطمُب بِِه بَ َدلً
ِ ِ ِ َعمى اهلُدى ل َم ِن استَُدى أَدّلءُ ِ ِ ِ َولم ِرجال َعمى األَفعال امساءُ ِِ الناس َموتى َو ُأه ُل العم أَحياءُ فَ ُ كرم اهلل وجهو علي ّ اإلمام ّ
27
الفصل األوّل :
لع ّل أفضل ما نبدأ به رحلتنا مع هذه اللغة هو البرنامج الشهٌر الذي ٌتم ّتع ببساطته إضافة الحتوابه على المكوّ نات الربٌس ٌّة التً الب ّد منها فً كل برنامج ,ولٌس علٌك اآلن لكً تكون مبرمجا سوى أن تضع أناملك الناعمة تلك على لوحة المفاتٌح .اآلن هل أنت مستع ّد لكتابة أوّ ل برنامج لك؟ إذن ه ٌّا بنا. افتح المترجم واكتب فٌه النصّ الذي على ٌسار الشكل ث ّم اضغط على أزرار التشغٌل !Hello World
// my first program in C++ >#include <iostream ;using namespace std )( int main { ;"!cout << "Hello World ;return 0 }
واتح التىفيذ( الخزج )
الشيفزة
تهانٌنا! كان هذا أوّ َل برنامج لنا فً ,C++واآلن دعنا نبدأ بشرح هذه العبارات // my first program in C++ هذا السطر ٌدعى تعلٌقا ,فكل السطور التً تبدأ بـ //تعتبر تعلٌقات وهذه التعلٌقات لٌس لها أي تؤثٌرعلى البرنامج.لقد جرت عادة المبرمجٌن على استخدام التعلٌقات لتوضٌح ومراقبة عمل الشٌفرة من داخل ملف المصدر. >#include <iostream ّ الجمل التً تبدأ بالرمز) (#هً عبارات تقوم بتوجٌه المترجم وال ٌت ّم تنفٌذها أثناء تنفٌذ الشٌفرة التً نكتبها لكنها تعمل كدلٌل للمترجم ,ففً مثالنا الجملة > #include <iostreamتخبر المترجم بؤن ٌقوم بتضمٌن الملف المصدري iostreamوهو ملف مع ّرف سابقا ٌحتوي على تصرٌحات للمكتبة القٌاسٌة الخاصة باإلدخال واإلخراج فً لغة C++وقد استدعٌنا هذه المكتبة أل ّننا سنستخدمها الحقا فً برنامجنا ,وكؤننا نقول للمترجم: "إننا سوف نستخدم التوابع المعرفة فً هذا الملف المصدري لذلك اذهب وأحضره" ,وسنؤتً على شرح ذلك الحقا. ;using namespace std جمٌع مكوّ نات المكتبة القٌاسٌة للغة C++معرّ فة فٌما ٌدعى بفضاء االسم ) (namespaceالذي سنشرحه الحقا. ومن أجل الوصول إلى العدٌد من التعلٌمات واألوامر الجاهزة فإنّ هذا السطر ٌتكرّ ر كثٌرا فً البرامج التً تستخدم المكتبة القٌاسٌة حٌث سترى هذا السطر فً معظم البرامج الموجودة فً هذا الكتاب. )(int main ٌمثل هذا السطر بداٌة التصرٌح عن التابع الربٌسً .main إنّ التابع mainهو النقطة األولى لبداٌة أي برنامج مكتو ٍ ب بلغة .C++وهذا الٌعتمد على كون هذا التابع مكتوبا فً أوّ ل الشٌفرة أو فً وسطها أو فً آخرها فؤٌنما كان هذا التابع مكتوبا فإنّ التنفٌذ سٌبدأ منه أي أ ّنه ضروريّ ج ّدا لٌعمل البرنامج ومن دونه ال ٌوجد برنامج. فً التصرٌح عن التابع mainوضعنا القوسٌن ) ( بعد اسم التابع وذلك ألنّ الصٌغة العا ّمة للتصرٌح عن التوابع تقضً بذلك كما سٌرد معنا فٌما بعد. ك ّل التعلٌمات التً سٌقوم التابع mainبتنفٌذها محصورة بٌن القوسٌن} { كما هو مبٌن فً المثال السابق.
28
;"!cout << "Hello World هذه التعٌلمة هً األكثر أهمٌة فً هذا البرنامج .تعتبر coutتعلٌمة قٌاسٌة فً C++وهً تقوم بطباعة الجملة Hello Worldعلى الشاشة. ومن الجٌد التنوٌه إلى أن التعلٌمة coutمعرّ فة فً الملف المصدري iostreamوقد قمنا بتضمٌنه فً بداٌة برنامجنا كً نتمكن من استخدامها. مالحظة :من المه ّم أن تعرف أنّ ك ّل تعلٌمة فً ٌ C++جب أن تنتهً بفاصلة منقوطة );(. )من األخطاء الشابعة بٌن مبرمجً C++أ ّنهم ٌن َسون وضع الفاصلة المنقوطة فً نهاٌة بعض التعلٌمات م ّما ٌُحدث خطؤ ٌمنع البرنامج من العمل ,فانتبه لذلك(. ;return 0 تقوم التعلٌمة returnبإنهاء التابع )( mainوتعٌد التعلٌمة التً تؤتً بعدها كقٌمة للتابع ,فً حالتنا هذه تعٌد .0 هذه هً الطرٌقة المعتادة إلنهاء البرنامج فعندما ٌعٌد التابع )( mainالقٌمة 0نعلم أنّ البرنامج انتهى دون أ ٌّة أخطاء أثناء ال ّتنفٌذ. ومن ث ّم البد أ ّنك قد الحظت أنّ كل سطر فً هذا البرنامج قام بعمله ,فالتعلٌق الذي بدأ بالرمز ) (//الذي وجّ ه المترجم ألن ٌتجاهل هذا السطر ,وهناك السطر الذي بدأ بالرمز) (#الذي وجّ ه المترجم كً ٌجلب الملف المصدري ,iostreamوكان هناك السطر الذي صرّ حنا به عن التابع )( ,mainوأخٌرا التعلٌمة coutالتً صٌن بالتابع .main وضعناها بٌن القوسٌن } { الخا ّ
تنسٌق الكتابة ٌمكننا أن نكتب: } ;int main () { cout << " Hello World "; return 0 ك ّل تعلٌمة فً C++تنتهً بالفاصلة المنقوطة كما ذكرنا .لذلك ال فرق فً أن تكتب ال ّتعلٌمات على سطر واحد أو فً ع ّدة أسطر ,فطالما أ ّنك لم تضع فاصلة منقوطة فهذا ٌعنً أنّ ال ّتعلٌمة لم تنت ِه بعد. لك ّننا كتبناه كما فً الجدول لكً تسهل قراءته. واآلن سنكتب المثال التالً بطرٌقة أخرى ممكنة Hello World! I'm a C++ program
// my second program in C++ >#include <iostream ;using namespace std )( int main { << cout ;" !"Hello World << cout ;""I'm a C++ program ;return 0 }
وٌجب االنتباه إلى أنّ الموجِّ هات )األسطر التً تبدأ بـ ُّ (# تشذ عن هذه القاعدة أل ّنها فً واقع األمر ال ّ تمثل تعلٌمات حقٌق ٌّة فهً أسطر ٌقرإها المترجم لك ّنها ال ّ تمثل أيّ جزء من شٌفرة البرنامج ,فهذه األسطر ٌجب أن تكتب فً مكانها الخاص فً أعلى البرنامج وهً ال تحتاج إلى فواصل منقوطة فً نهاٌاتها.
29
التعلٌقات ال ّتعلٌق هو قطعة من الشٌفرة مهملة من قبل المترجم .إذن التعلٌقات ال تقوم بؤ ٌّة وظٌفة برمجٌة ,وإ ّنما هً موجودة فقط لتذ ّكر المبرمج ببعض المبلحظات حول شٌفرته. تق ّدم C++نوعٌن من التعلٌقات هما كاآلتً: تعلٌق على نفس السطر تعلٌق على سطر أو أكثر
// line comment /* block comment */
واآلن لنضف بعض التعلٌقات إلى برنامجنا السابق Hello World! I'm a C++ program
/* my second program in C++ With more comments */ >#include <iostream ;using namespace std )( int main { //says hello world
;" !cout<<"Hello World //says I'm a C++ program
;"cout<<"I'm a C++ program ;return 0 }
تنس استخدام أحد الرمزٌن //أو /* */ مالحظة :عندما ترٌد أن تضٌف تعلٌقا َ ما فعلٌك ّأال َ ألنّ ذلك سٌتسبب بؤخطاء .إذ أنّ المترجم سٌعتبر هذه األسطر تعلٌمات بدال من أن ٌعتبرها تعلٌقات وهذا ما ال ترٌده أنت وال المترجم طبعا.
.2امؤل الفراغات التالٌة : كل برنامج فً ٌ C++بدأ من التابع ______. كل عبارة فً C++تنتهً بـ ______. الرمز ٌ //دل على أن هذا السطر ______. التعلٌقات هً ________________________. التعلٌمة ; return 0تعمل على __________________. التعلٌمات الخاصة بالتابع mainموجودة بٌن ______. التعلٌمة > #include<iostream.hتعنً __________________. .3اجعل البرنامج السابق ٌطبع العبارة التالٌة : !In the name of Allah. The peace upon you, Hello world
2:
الفصل الثاني:
إنّ الفابدة من برنامج hello worldالذي قمنا بإنشابه فً الدرس السابق هً أن نعرض نصّا ما على شاشة الحاسب ,لكن هل البرمجة محدودة إلى هذه الدرجة؟ لنفترض أ ّننً طلبت منك أن تحتفظ بالرقم 4فً ذهنك ث ّم طلبت منك أن تحتفظ بالرقم ,1اآلن رجاء أضف 4 إلى الرقم األوّ ل ,ث ّم اجمع الرقم األوّ ل إلى الرقم الثانً وأعطنً الناتج. ٌمكن أن نعبِّر برمجٌا عن ذلك كما ٌلً: ;a=4 ;b=1 ;a=a+3 ; result = a + b إنّ الحاسب ٌقوم بإجراء هذه العملٌات تماما كما تقوم أنت بها ,لكنه ٌتم ٌّز عنك بؤ ّنه قادر على االحتفاظ بآالف قصٌر جدّا وهذا ٌت ّم من خبلل إدخال القٌم إلى الحاسب القٌم وإجراء عشرات العملٌات الحسابٌة المع ّقدة فً وقت ٍ وتخزٌنها فً أماكن مخصّصة فً الذاكرة ندعوها بالمتغٌّرات. المتغ ٌّرات :هً أماكن )خبلٌا( فً الذاكرة المإ ّقتة ّ تخزن فٌها البٌانات ,وٌت ّم الوصول إلٌها من خبلل اسم المتغٌّر الذي ٌم ٌّزه عن باقً المتغٌّرات فً الذاكرة. كٌف نسمً المتغ ٌّرات؟ إنّ االسم الصحٌح للمتغٌّر ٌتؤلف من سلسلة م ّتصلة مكوّ نة من محرف أو أكثر ,و ٌمكن أن تحوي أرقاما أو الرمز) _ ( .شرٌطة أن ٌبدأ اسم المتغٌّر بحرف أو بـ ) _ (ّ , وأال ٌبدأ برقم أو ٌحوي على فراغات أو رموز صة مثل....$ # .- @ : خا ّ هل هناك طول معٌن السم المتغ ٌّر؟ اسم المتغٌّر لٌس محدودأ ,ولكنّ بعض المترجمات تقبل فقط الـ 23حرفا األولى من اسم المتغٌّر إنّ طو َل ِ وتهمل باقً األحرف. قاعذة أخزِ يجب عليل أن تضعٍا في حسباول :اسم المتغيّز ال يمنه أن ينُن إحذِ النلماث المحجُسة في لغت ٌ َ C++ذي النلماث ٌي:
asm, auto, bool, break, case, catch, char, class, const, const_cast, continue, default, delete, do, double, dynamic_cast, else, enum, explicit, extern, false, float, for, friend, goto, if, inline, int, long, mutable, namespace, new, operator, private, protected, public, register, reinterpret_cast, return, short, signed, sizeof, static, static_cast, struct, switch, template, this, throw, true, try, typedef, typeid, typename, union, unsigned, using, virtual, void, volatile, wchar_t َيضاف إليٍا مجمُعت العملياث المىطقيت التاليت:
and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor, xor_eq
31
حساسٌة اللغة لحالة األحرف: إنّ لغة C++ح ّساسة لحالة األحرف فعندما تكتب اسم المتغٌّر علٌك أن تراعً حالة ك ّل حرف من حروفه واألمثلة التالٌة كفٌلة بشرح هذه الفكرة إن شاء هللا: فً المثال السابق المتغٌّر ٌ aختلف تماما عن المتغٌّر ,Aوكذلك كل المتغٌّرات التالٌة مختلفة … Result , result , RESULT أي أ ّنه لو قمنا بالتصرٌح عن متغٌّر ما باالسم aفلن ٌكون بمقدورنا أن نستدعٌه إال باالسم aولو استدعٌناه آخر وهو غٌر موجود. باالسم Aفلن ٌعرفه المترجم أل ّنه سٌعتبره متغٌّرا َ
أنواع البٌانات )(Data types عندما نكتب برنامجا فإ ّننا سنحتاج إلى تخزٌن البٌانات فً الذاكرة باستخدام المتغٌّرات مما ٌعنً أ ّننا سنحجز مساحة فً الذاكرة لك ّل واح ٍد من المتغٌّرات التً سنتعامل معها. نخزن ّ لكن هل لكل ّ المتغ ٌّرات نفس الحجم فً الذاكرة؟ لتوضٌح هذه المسؤلة لنفترض أ ّننا نرٌد أن ّ كبل من القٌم التالٌة 10و 45.123و .Hi Everybody إنّ ذاكرة الحاسب مقسّمة إلى وحدات تدعى باٌتات .Bytesوالباٌت هو وحدة قٌاس الحجم الصغرى التً سنتعامل معها .نستطٌع أن نخ ّزن فً الباٌت الواحد عددا صحٌحا بٌن 1و 366أو حرفا أو رمزا واحدا فقط. واضح تماما أ ّننا لن نستخدم فقط األرقام من 1إلى ,366ولن ندخل حرفا واحدا فقط فنحن بحاجة ألكثر من ذلك بكثٌر لذلك ٌو ّفر لنا الحاسب أنواعا أخرى أكثر تعقٌدا من النوعٌن السابقٌن وذلك بتجمٌع عدّة باٌتات إلى بعضها لت ّتسع لحجم أكبر من البٌانات) .كما هو موضح فً الشكل(
32
نعرض فً الجدول التالً عدّ ة أنواع من البٌانات المستخدمة فً .C++
نوع المتغ ٌّر
الحجم بالباٌت
مالحظات
المدى (ٌمثل القٌم التً ٌمكن للمتغ ٌّر أن ٌأخذها)
char
2
بإشارة ][-128,127 دون إشارة ][0,255
حرف واحد أو رقم طوله 8بِت
short
3
بإشارة ][-32768 , 32767 دون إشارة ][0,65535
رقم صحٌح طوله 06 بِت
long
5
بإشارة ][-2147483648 , 2147483647 دون إشارة ][0,53:5:783:6
رقم صحٌح طوله 23 ِبت
int float
3أو 5 5
إما shortأو long إلى
رقم صحٌح رقم عشري
double
9
long double
21
bool
2
إلى إلى trueأو false
) 8أرقام( ) 26رقم( ) 26رقم(
رقم ذو دقة عشرٌة مضاعفة عن float رقم ذو دقة عشرٌة مضاعفة عن double متغ ٌّر منطقً بإحدى القٌمتٌن 1أو 0
واآلن لنعد إلى موضوعنا الذي ك ّنا بدأنا الحدٌث عنه سابقا. نصرح عن المتغ ٌّرات؟ ك ّنا نقول :كٌف ٌمكننا أن ّ نذكر اسمه وفقا نذكر نوع البٌانات )… (int, short, float,التً سٌؤخذها المتغٌّر ,ث ّم تفرض علٌنا اللغة أن َ َ لقواعد التسمٌة التً أوردناها للتو .أي أنّ التصرٌح عن المتغٌّرات ٌخضع للقاعدة التالٌة: ; data_type variable_Identifier أو
; data_type variable_Identifier = initial_value أمثلة: ; int a ; float mynumber ; long mysecondnumber = 5 كما تبلحظ بدأ التصرٌح عن المتغٌّر aبالنوع intأي أ ّننا نقول للمترجم" :إنّ المتغٌّر هو من نوع األعداد الثانً .أمّا المثال ّ الصحٌحة intو اسمه ,"aوكذلك األمر فً المثال ّ الثالث فقد تابعنا الخطوات بؤن قمنا بتبدبته )أي إسناد قٌمة ابتدابٌة للمتغٌر أثناء التصرٌح عنه( على القٌمة .5 تم ّكننا C++من التصرٌح عن عدّة متغٌّرات من نفس النوع وتبدبتها إن أردنا فً سطر واحد. مثال:
وهذا مكافا تماما لل ّشكل التالً:
; int a, b = 3, c = 5 ; int a ; int b = 3 ; int c = 5
33
لعلّك الحظت من الجدول أنّ األنواع ( )int , short , long, charتكون بإشارة أو بدون إشارة وهذا تابع للمجال الذي نرغب بؤن ٌضمّه المتغٌّر ففً بعض الحاالت نكون واثقٌن بؤنّ القٌم التً سٌؤخذها متغٌّر عدديّ هً من ال ّنوع الصّحٌح و الموجب فقط عندها قد ال نرغب بؤن ٌكون المتغٌّر معرّ فا لٌستقبل األعداد السالبة. تستطٌع أن تح ّدد فٌما إذا كان المتغٌّر من األنواع األربعة السابقة ٌمتلك إشارة أو ال وذلك باستخدم إحدى الكلمتٌن التالٌٌن: ; unsigned short NumberOfSons ; signed int MyAccountBalance فً الحالة األولى من المعروف أنّ عدد األبناء ال ٌمكن أن ٌكون أقل من الصفر فإمّا أن ٌكون هناك أبناء أو ال ٌكون لذلك صرّ حنا عن NumberOfSonsعلى أ ّنه بدون إشارة سالبة. أمّا فً الحالة الثانٌة فبل شًء ٌضمن عدم إدخال قٌمة سالبة على المتغٌّر MyAccountBalance ( داللة على الخسارة مث اال ) لذلك صرّ حنا عنه على أ ّنه من النوع signedالذي ٌستطٌع أن ٌحمل أرقاما سالبة. وبشكل افتراضً إذا لم تحدد فٌما إذا كان المتغٌّر من النوع signedأو unsignedفإنّ المترجم سٌعتبره من النوع signedلذلك ٌمكن التصرٌح عن المتغٌّر فً الحالة الثانٌة من المثال السابق بالشكل: ; Int MyAccountBalance وهذا هو الشكل المعتاد لهذه الحالة. واآلن لنكتب المثال الذي بدأنا به درسنا 16
// operating with variables >#include <iostream ;using namespace std )( int main { // declaring variables: ;int a, b ;int result // process: ;a = 10 ;b = 4 ;a = a + 2 ;result = a + b // print out the result: ;cout << result // terminate the program: ;return 0 }
مالحظة :إنّ الطرٌقة السابقة بتبدبة المتغٌّرات مؤخوذة من لغة ,Cوهذا ما ٌدعى ) ,(C-Likeلكنّ C++تمتلك طرٌقة أخرى لفعل ذلك وهً : ; )data_type variable_Identifier (initial_value ; int a = 5 ; )int a (5 أي أنّ :
34
) strings ( مق ّدمة إلى السالسل C++ توجد فً لغة. ٌعبّر عن سلسلة من الرموز المحفوظة فً حجرات متتالٌة من الذاكرةstring إنّ النوع سنشرحها الحقا فً فصلC-style string وتدعىC األولى مؤخوذة من لغة,طرٌقتان للتعامل مع السبلسل .STL ومكتبة القوالب القٌاسٌةstring ّسبلسل الرموز أمّا الطرٌقة الثانٌة فتعتمد على الصف <string> ٌجب أن نضمّن الملف المصدريstring لكً نستطٌع أن نتعامل مع السبلسل // my first string #include <iostream> #include <string> using namespace std;
enter your name: Basil Hello Basil
int main () { string name; cout<<"enter your name: "; cin>>name; cout << "Hello "<<name<<endl; return 0; }
ّ تقوم بنقل المإendl التعلٌمة .شر إلى السطر التالً كما سنرى فٌما بعد
(<,>) ( والمقارنة+=) ( واإلضافة+) كالجمعstring ّهناك مجموعة من العمل ٌّات المعرّ فة فً الصف :مثال // my second string #include <iostream> #include <string> using namespace std; int main () { string firstName,lastName,fullName; cout<<"enter your first name: "; cin>>firstName; cout<<"enter your last name: "; cin>>lastName; fullName=firstName+" "+lastName; cout<<"Hello "<<fullName<<endl; if(firstName<lastName) cout<<firstName<<endl; return 0; }
35
enter your first name: Ahmad enter your last name: Sami Hello Ahmad Sami Ahmad
.2أجب عن األسبلة التالٌة : هل المتغٌّر Numهو نفس المتغٌّر numفً C++؟ هل ٌجب أن ٌعطى المتغٌّر نوعا من البٌانات عند التصرٌح عنه ؟ هل ٌمكن أن تكون أسماء المتغٌّرات أي مجموعة من الرموز ؟ هل نستطٌع أن نعرّ ف متغٌّرا ونعطٌه قٌمة فً نفس اللحظة ؟ ما الفرق بٌن المتغٌّرات signedو . unsigned .3امؤل الفراغات التالٌة : المتغ ٌّرات هً ______ فً ذاكرة الحاسب ______فٌها البٌانات ,وٌت ّم الوصول إلٌها من خبلل ______المتغٌّر الذي ______عن باقً المتغٌّرات فً ______. .4اختر اإلجابة الصحٌحة؟ ; unsigned long f = -1.25 ; int 4men ;'double d = 'S ; long _2u ; short hi. ; "char u = "U
)a )b )c )d )e )f
.5ما هً األخطاء فً البرنامج التالً: >#include <iostream ;using namespace std )( int main { ; float a = 1 , b = 0 ;unsigned int result ;a = a - 6 ;result = A + b ;cout << result }
36
الفصل الثالث :
تو ّفر المكتبة iostreamالتعلٌمتٌن cinو coutحٌث ت ّم تصمٌ ُم ُه َما من أجل التخاطب بٌن المستخدم والحاسب, وذلك أنّ العمل ٌّة coutتقوم بالطباعة على الشاشة بٌنما تقوم العملٌة cinبإدخال القٌم التً ٌحتاجها البرنامج من لوحة المفاتٌح.
تعلٌمة اإلخراج )(cout تعاملنا مع هذه التعلٌمة منذ أوّ ل درس لنا فً C++لذلك فؤنا واثق بؤ ّنك تدرك وظٌفتها ,ولك َّنه من األفضل أن البق بصاحبة الجبللة .cout شرح أق ّدم إلٌك تذكٌرا مع ٍ ٍ تعمل هذه التعلٌمة على إخراج قٌم المتغٌّرات والثوابت التً تؤتً مباشرة بعد معامل الحشر >> ,ولها الشكل التالً: cout<< "Islam is a way of life" ; // print Islam is a way of life on screen // print number 120 on screen // print the content of variable x on screen
; cout<< 120 ; cout<< x
مالذي تفعله هذه التعلٌمات؟ -0التعلٌمة األولى :تطبع هذه التعلٌمة العبارة Islam is a way of lifeالمحصورة بٌن عبلمتً التنصٌص " " على شاشة الخرج( .عندما نرغب بطباعة نص ما فعلٌنا أن نضعه بٌن قوسً التنصٌص وكذلك األمر عند إسناد نص إلى متغٌّر نصً لذلك فالعبارتٌن اآلتٌتٌن مختلفتٌن تماماا).
رطجغ اٌؼجبسح ث ٓ١لٛع ٟاٌزٕظ١ض ٟ٘ٚاٌىٍّخ cout<< "Hello" ; // Hello رطجغ لّ١خ اٌّزغّ١ش cout<< Hello ; // Hello -3التعلٌمة الثانٌة :تطبع الرّ قم 031على شاشة الخرج. ّ المخزنة فً المتغٌّر xعلى شاشة الخرج. -2التعلٌمة الثالثة :تطبع القٌمة تستطٌع أن تستخدم أكثر من معامل حشر واحد << فً نفس التعلٌمة: ; " cout<< "The peace upon you, " << "I am " << "a C++ sentence. هذه العبارة تطبع الجملة التالٌة:
The peace upon you, I am a C++ sentence. تكمن الفابدة من استخدام أكثر من معامل حشر فً نفس التعلٌمة فً طباعة عبارة مر ّكبة من قٌم ثابتة ومتغٌّرات كما فً المثال التالً: ; cout<<"I am "<< age << " years old and my zipcode is "<< zipcode
37
عندها فإنّ ناتج التعلٌمة42296 ٌحمل القٌمةzipcode والمتغٌّر32 ً هage لو افترضنا أن قٌمة المتغٌّر :السابقة سٌكون I am 20 years old and my zipcode is 60094 \) فهً تطبع على سطرnew line( \n ال تقوم بإضافة رمز انتهاء السطرcout ٌجب أن تعلم أنّ التعلٌمة لتوضٌح هذه. لذلك عندما ترغب فً الطباعة على سطر جدٌد فعلٌك أن تضٌف هذا الرّ مز بنفسك.واحد :المسؤلة :ًلنقل إ ّننا نرٌد أن نطبع الشكل التال Go forward young Muslims, wherever you are In the shadow of the sun or by the light of a star :ًعندها قد نكتب التال cout<< "Go forward young Muslims, wherever you are"; cout<< " In the shadow of the sun or by the light of a star"; :ًلكنّ المفاجؤة عندما نشغل البرنامج فشكل الطباعة سٌكون كاآلت Go forward young Muslims, wherever you are In the shadow of the sun or by the light of a star
والحل ٌكمن كما قلنا,وهذا ما ال نرٌده فالعبارتان على سطر واحد بٌنما نرٌد أن تكون كل واحدة على سطر :\ فً نهاٌة التعلٌمة األولى لتصبح بالشكلn للتوّ بإضافة الرمز cout<< " Go forward young Muslims, wherever you are\n"; : ث ّم ٌقو َم بتنفٌذ التعلٌمة الثانٌة,عندها سٌعلم المترجم أ ّنك ترٌد منه أن ٌبدأَ سطرا جدٌدا cout<< " In the shadow of the sun or by the light of a star"; ) وعندها سٌكون شكل البرنامجend line( endl \ وهً التعلٌمةn هناك تعلٌمة بدٌلة عن رمز االنتهاء :ًكاآلت cout<< " Go forward young Muslims, wherever you are"<<endl; cout<< " In the shadow of the sun or by the light of a star"; :سنقدّم مثاال نذكر من خبلله بعض الطرق الممكنة الستخدام هاتٌن التعلٌمتٌن #include<iostream> using namespace std; int main() { /* **** 1 **** */ cout<< "Welcome to you\n"; cout<<"C++ You are elegant"<< endl; /* **** 2 **** */ cout<< "Welcome to you "<< endl; cout<<"C++ You are elegant\n"; /* **** 3 **** */ cout<< "Welcome to you\nC++ You are elegant"<< endl; /* **** 4 **** */ cout<< "Welcome to you"<< endl <<"C++ You are elegant\n"; /* … */ return 0; } Welcome to you C++ You are elegant
38
تعلٌمة اإلدخال )input (cin تستخدم هذه التعلٌمة إلدخال القٌم المطلوبة من لوحة المفاتٌح ,ونستخدم لذلك معامبل ٌدعى معامل اإلدخال << ث ّم نتبعه باسم المتغٌّر الذي نرغب بإعطابه القٌمة المقروءة من لوحة المفاتٌح ,وذلك كما ٌلً: ; int age ; cin>> age مثال: >#include <iostream ;using namespace std )( int main { ;int i ;" cout << "Please enter an integer value: ;cin >> i ;cout << "The value you entered is " << i ;"cout << " and its double is " << i*2 << ".\n ;return 0 } Please enter an integer value: 702 The value you entered is 702 and its double is 1404.
مالحظة :2قد ٌكون المستخدم أحد أه ّم العوامل التً تسبب فشل برنامجك ففً المثال السابق طلبنا من المستخدم أن ٌدخل رقما صحٌحا ,ولكن ماذا لو أدخل المستخدم اسمه؟ بالطبع لن تكون مسرورا لذلك. طبعاً ٌىاك حل لمثل ٌذي المشامل َلنىّىا له وتحذث عىً ٌىا َإو ّما أردوا التىبيً لمثل ٌذي المشامل حتّ تضعٍا في حسباول.
مالحظة ٌ :3مكن أن نستخدم التعلٌمة cinإلدخال أكثر من قٌمة كما ٌلً: ; cin >> a >> b
بعض الرموز الخاصة سطر جدٌد ٌكافا الضغط على زر مسافة جدولة أفقٌة تراجع ٌصدر صوتا تطبع الرمز تطبع الرمز
New line Enter Tabulation Back space Beep
' "
\n \r \t \b \a '\ "\
39
.2مالذي تطبعه التعلٌمة التالٌة: ; " *****cout<<"*\n**\n***\n****\n .3اكتب برنامج ٌقرأ درجة الحرارة بالسٌلٌسوس ) ,(cث ّم ٌحولها إلى الفهرانهاٌت وفق العبلقة .2اكتب برنامج ٌقرأ درجة الحرارة بالفهرانهاٌت ) ,(fث ّم ٌحولها إلى مبوٌة وفق العبلقة – .6اكتب برنامجا ٌقرأ تسارع جسم ما aو الزمن tالذي استغرقه فً الحركة ث ّم ٌحسب: المسافة المقطوعة و السرعة النهابٌة .5اكتب برنامجا ٌحسب قٌمة التابع التالً .4إذا علمت أن مجموع األعداد من 1إلى العدد ٌ nعطى بالعبلقة التالٌة ∑ اكتب برنامجا باستخدام هذه العبلقة لحساب مجموع األعداد من 1إلى nالتً ٌدخلها المستخدم ث ّم احسب المتوسط الحسابً لها .7اكتب برنامجا ٌطبع العبارةJust remember "Allah created You'. : .8اكتب برنامجا ٌحسب المتوسط الحسابً لثبلثة أعداد ٌدخلها المستخدم.
3:
โ ซุงู ู ุตู ุงู ุฑุงุจุน โ ช:โ ฌโ ฌ
โ ซู ู ู ุซู ุฑ ู ู ุงุฃู ุญู ุงู ู ุญุชุงุฌ ุฅู ู ุฃุฑู ุงู ุฃู ู ุตู ุต ุซุงุจุชุฉ ุงู ุณุชุฎุฏุงู ู ุง ู ู ุจุฑุงู ุฌู ุงโ ช .โ ฌู ุฏ ุงู ู ู ู ู ุฐู ู ู ุงุถุญุง ู ู โ ฌ โ ซุงู ุจุฑุงู ุฌ ุงู ุนุงุฏู ุฉ ุฃู ุงู ุจุณู ุทุฉ ู ู ู ู ู ู ู ุชุถุญ ู ู ุงู ุจุฑุงู ุฌ ุงู ู ุจู ุฑุฉ ุงู ุชู ุชุชุนุงู ู ู ุน ุงู ุฏู ุง ู ู ุงู ุฑู ุงุถู ู ุฉ ู ุงู ุฑุณู ู ู ุบู ุฑู ุงโ ช.โ ฌโ ฌ โ ซู ู ู ุคุฎุฐ ู ู ุซุงู ุงู ุฑู ู ุงู ู ุนุฑู ู ๐ ุงู ุฐู ู ุซู ุฑุง ู ุง ู ู ุณุชุฎุฏู ู ู ุงู ุญุณุงุจุงุช ุงู ุฑู ุงุถู ุฉโ ช .โ ฌู ุนู ู ุฃ ู ู ู ู ู ู ู ุง ุฒุงุฏุช ุฏ ู ู ุฉ ุงุฃู ุฑู ุงู โ ฌ โ ซุงู ุนุดุฑู ู ุฉ ุฒุงุฏุช ุฏ ู ู ุฉ ุงู ุญุณุงุจุงุชโ ช ,โ ฌู ู ู ู ุชุฑุถ ุฃ ู ู ู ุง ุณู ุณุชุฎุฏู ุงู ุฑู ู ๐ ู ู ุจุฑู ุงู ุฌู ุง ุนุฏู ุฉ ู ุฑู ุงุช ู ู ู ุณู ู ู ู ู ุถุทุฑู ู ู โ ฌ โ ซู ู ุชุงุจุฉ ู ุฐุง ุงู ุฑู ู ู ุนุฏู ุฉ ู ุฑู ุงุชโ ช .โ ฌุฅู ู ู ุฐู ุงู ุทุฑู ู ุฉ ุชุนู ู ุฒู ุงุฏุฉ ุงุญุชู ุงู ู ู ู ุน ุฃุฎุทุงุก ู ู ุฏ ู ุฎุทุง ุจู ุชุงุจุฉ ุงู ุฑู ู ู ู ู ู ุง ู ุนู ู โ ฌ โ ซุฎุทุค ุญุณุงุจู ุง ู ุฏ ู ุชุณุจุจ ุจู ุงุฑุซุฉ ู ุจู ุฑุฉ ู ู ุงู ุจุฑุงู ุฌ ุงู ู ู ุฏุณู ู ุฉ ุฃู ุงุฅู ู ุดุงุจู ู ุฉ ู ุฐู ู ู ู ุฑู ุช ู ุบุงุช ุงู ุจุฑู ุฌุฉ ู ุง ู ุณู ู ู โ ฌ โ ซุจุงู ุซู ุงุจุช ู ุคู ุช ุชุตุฑุญ ุนู ุงู ุซุงุจุช ู ุชุนุทู ู ุงู ู ู ู ุฉ ุงู ุชู ุณู ุคุฎุฐู ุง ู ุงู ุชู ุงู ู ู ู ู ุฃู ุชุชุบู ุฑ ุทู ุงู ู ุชุฑุฉ ุงู ุชู ู ู ุฐ ุซ ู ู โ ฌ โ ซุชู ู ู ุจุงุณุชุฏุนุงุก ุงู ุซุงุจุช ู ู ู ู ู ุฑู ุฉ ุชู ู ุฏ ุงุณุชุฎุฏุงู ู ู ู ู ุงโ ช.โ ฌโ ฌ
โ ซู ู ู ู ุตุฑุญ ุนู ุงู ุซู ุงุจุชุ โ ฌ โ ซู ู ุงู ุทุฑู ู ุชุงู โ ช:โ ฌโ ฌ โ ซโ ช ๏ ผโ ฌุงุฃู ู ู ู โ ช:constโ ฌโ ฌ โ ซ; โ ชconst float pi = 3.14159265โ ฌโ ฌ โ ซ; 'โ ชconst char tab = '\tโ ฌโ ฌ โ ซโ ช ๏ ผโ ฌุงู ุซุงู ู ุฉ โ ช:#defineโ ฌโ ฌ โ ซโ ช#define pi 3.14159265โ ฌโ ฌ โ ซ'โ ช#define NewLine '\nโ ฌโ ฌ โ ซู ู ู ุฐู ุงู ุญุงู ุฉ ู ุณุชุฎุฏู ุงู ุชุนู ู ู ุฉ โ ช #defineโ ฌุซ ู ู ู ุฐู ุฑ ุงุณู ุงู ุซุงุจุช ุซ ู ู ุงู ู ู ู ุฉ ุงู ุชู ุณู ุคุฎุฐู ุงโ ช .โ ฌุงู ุชุจู โ ช :โ ฌู ู ู ุฐู ุงู ุทุฑู ู ุฉ ุงู โ ฌ โ ซู ู ุฌุฏ ู ุงุตู ุฉ ู ู ู ู ุทุฉ ู ู ู ู ุงู ุฉ ุงู ุชุนู ู ู ุฉโ ช.โ ฌโ ฌ โ ซู ุนู ู ู ุงู ุญุธุช ุฃ ู ู ู ุง ู ู ู ู ู ุจุชุญุฏู ุฏ ู ู ุน ุงู ุซุงุจุช ู ู ุงู ุญุงู ุฉ ุงู ุซุงู ู ุฉ ู ู ุง ู ุนู ู ุง ู ู ุงู ุญุงู ุฉ ุงุฃู ู ู ู โ ช.โ ฌโ ฌ โ ซุงู ุญุงู ุฉ ุงุฃู ู ู ู โ ฌ โ ซ>โ ช#include<iostreamโ ฌโ ฌ โ ซ;โ ชusing namespace stdโ ฌโ ฌ โ ซ;โ ชconst double pi = 3.14159265โ ฌโ ฌ โ ซ)(โ ชint mainโ ฌโ ฌ โ ซ{โ ฌ โ ซ; โ ชfloat rโ ฌโ ฌ โ ซโ ชr = 0 ;//initial to 0โ ฌโ ฌ โ ซ;" โ ชcout<<"enter circle radius plz:โ ฌโ ฌ โ ซ; โ ชcin>> rโ ฌโ ฌ โ ซ" = โ ชcout<< "circle areaโ ฌโ ฌ โ ซ;โ ช<< 0.5 * pi * r * r << endlโ ฌโ ฌ โ ซ; โ ชreturn 0โ ฌโ ฌ โ ซ}โ ฌ
โ ซุงู ุญุงู ุฉ ุงู ุซุงู ู ุฉโ ฌ
โ ซโ ช0โ ฌโ ฌ โ ซ;" โ ชradius plz:โ ฌโ ฌ โ ซ" =โ ฌ โ ซ;โ ช* r << endlโ ฌโ ฌ
โ ซ>โ ช#include<iostreamโ ฌโ ฌ โ ซ;โ ชusing namespace stdโ ฌโ ฌ โ ซโ ช#define pi 3.14159265โ ฌโ ฌ โ ซ)(โ ชint mainโ ฌโ ฌ โ ซ{โ ฌ โ ซ; โ ชfloat R ,rโ ฌโ ฌ โ ซโ ชr = 0 ;//initial toโ ฌโ ฌ โ ซโ ชcout<<"enter circleโ ฌโ ฌ โ ซ; โ ชcin>> rโ ฌโ ฌ โ ซโ ชcout<< "circle areaโ ฌโ ฌ โ ซโ ช<< 0.5 * pi * rโ ฌโ ฌ โ ซ; โ ชreturn 0โ ฌโ ฌ โ ซ}โ ฌ
โ ซโ ช41โ ฌโ ฌ
الفصل اخلامس :
تعرّ فنا فً الدرس السابق على المتغٌّرات والثوابت وقلنا" :إنّ المتغٌّرات هً األماكن التً ّ ٌخزن الحاسب فٌها البٌانات وهً مستعدّة لتغٌٌر قٌمتها أثناء تنفٌذ البرنامج ,بٌنما الثوابت فهً أماكن فً الذاكرة تحتفظ بقٌمة وحٌدة ال ٌمكن تغٌٌرها طوال فترة تشغٌل البرنامج" ,وتعرّ فنا أٌضا على كٌفٌة ال ّتصرٌح عن ك ّل منهما ,ولكن كٌف ٌمكننا التحكم بالقٌم التً تحتفظ بها المتغ ٌّرات؟ من أجل هذا تزوّ دنا C++بالمعامبلت .والتً ُت َّ مثل فً هذه اللغة بمجموعة من الكلمات المفتاحٌة المحجوزة والرموز الخاصة وهذه المعامبلت تعتبر من أساس ٌّات اللغة لذلك الب ّد لك عزٌزي القارئ من التعرف علٌها و التعامل معها بشكل جٌد.
.1اإلسناد (=) نستخدم معامل اإلسناد = كً نعطً المتغٌّر قٌمة من نوع
ٌقبله(كأن نضع رقم صحٌح فً متغٌّر من النوع العشري مثالا)
; float a = 3 أسند العدد الصحٌح 4إلى المتغٌّرالعشري ٌ .aقوم معامل اإلسناد بإسناد القٌمة على ٌمٌنه إلى المتغٌّر الذي على ٌساره حٌث أنّ القٌمة على الٌمٌن ٌمكن أن تكون متغٌّرا أو عددا ثابتا أو نتٌجة لعدد من العملٌات على قٌم موافقة لنوع المتغٌّر على ٌسارمعامل اإلسناد .واإلسناد المعاكس لٌس ممكنا. أمثلة: ?b: ?b: b:4 b:4 b:7 ; a = 2 + b ; 3) a = 7
? // a : // a : 10 // a : 10 // a : 4 // a : 4 )b = 5 ; 2
; int a , b ; a = 10 ;b=4 ;a=b ;b=7 )a = 2 + ( b = 5 ) ; // 1
أسند القٌمة 6إلى المتغٌّر bث ّم أسند المجموع ) (2 + bإلى المتغٌّر .a ; a = b = c = 5 ; //1( c =5 ; 2( b = c ; : c = 5 3) a = b ; : b = 5 أسند القٌمة 6إلى المتغٌّرات الثبلثة a , b , c
.2المعامالت الرٌاضٌة ()+, -, *, /, % تدعم C++خمس معامبلت رٌاض ٌّة وهً: العملٌة + Addition subtractionــ * multiplication / division % module
الوظٌفة ٌقوم بجمع القٌمتٌن على طرفٌه ٌقوم بطرح القٌمتٌن على طرفٌه ٌقوم بضرب القٌمتٌن على طرفٌه ٌقوم تقسٌم القٌمة التً علً ٌساره على القٌمة التً التً على ٌمٌنه ٌعٌد باقً قسمة القٌمة على ٌمٌنه على القٌمة على ٌساره
42
.3معامالت اإلسناد المركبة (=| )+=, -=, *=, /=, %=, &=, ^=, ;value += increase ;a -= 5 ;a /= b ;price *= units + 1
;value = value + increase ;a = a - 5 ;a = a / b ;)price = price * (units + 1 وكذلك باقً المعامبلت.
.4معامالت الزٌادة و النقصان ()++, -- ;a=a+1 ;a=a-1
; a+= 1 ; a-= 1
; a++ ; a--
مالحظة: ٌمكن استخدام هذٌن المعاملٌن بطرٌقتٌن مختلفتٌن و المثال التالً ٌبٌن ذلك: الطرٌقة األولى ;b = 3 ; a = b++ // a = 3 , b = 4
الطرٌقة الثانٌة ;b = 3 ;a = ++b // a = 4 , b = 4
ُتسند bإلى aث ّم تزداد bبمقدار 1تزداد bبمقدار 1ث ّم ُتسند bإلى a
الفرق فً كبل الطرٌقتٌن بدأنا مع b = 3 فً الطرٌقة 0تصبح a = 3ث ّم تزداد قٌمة bفتصبح b = 4أما فً الطرٌقة 2تزداد قٌمة bث ّم تصبح a=b=4
.5معامالت المقارنة ( =< ) ==, !=, >, <, >=, تستخدم هذه المعامبلت عادة للمقارنة بٌن عبارتٌن برمجٌتٌن ,وتعٌ ُد إحدى القٌمتٌن trueأو falseوذلك حسب نتٌجة المقارنة. المعامل == =! < > =< =>
وصفه ٌساوي ال ٌساوي أصغر من أكبر من أصغر أو ٌساوي أكبر أو ٌساوي
مثال ) ( 6 == 8ستعٌد false ) (3 != 4ستعٌد true ) ( 9 > 5ستعٌد false ) ( 9 > 5ستعٌد true ) (7 >= 7ستعٌد true ) (7 <= 7ستعٌد true
طبعا نستطٌع استخدام متغٌّرات أو تعابٌر للمقارنة بٌنها عوضا عن استخدام أرقام ثابتة فقط. لنفترض أنّ لدٌنا a = 2, b = 3, c = 6 تعٌد false ) ( a == 5 تعٌد true ) ( a * b >= c تعٌد false )(b+4>a*c تعٌد true ) ( ( b = 2 ) == a 43
كن حذراا :استخدام المعامل = مرّ ة واحدة فقط ٌعنً اإلسناد أمّا استخدامه مرّ تٌن == فٌعنً المقارنة والسطر الرابع من المثال السابق ٌوضح ذلك. فً العدٌد من المترجمات كما فً لغة Cمثبل تعٌد المعامبلت المنطقٌّة قٌما عددٌّة صحٌحة حٌث تعٌد القٌمة 1 بدال من falseوتعٌد قٌما مختلفة عن 1بدال من ( trueفً الحالة العامة تعٌد القٌمة .)0
.6المعامالت المنطقٌة (|| )!, &&, المعامل : ! not ) !( 5 == 5 ) !( 6 <= 4 !true !false
ٌعٌد falseألن 6تساوي 6 ٌعٌد trueألن 7لٌست أصغر من أو تساوي الـ 5 ٌعٌد false ٌعٌد true
المعامالن && و || : && ّ ٌمثل معامل الربط المنطقً ) َو ( and || ّ ٌمثل معامل الربط المنطقً ) أو ( or a true true false false
b true false true false
a && b true false false false
a || b true true true false
مثال ))((a ) && ( b)) , (( a) || ( b )) (( 5 == 5 ) && ( 3 < 6 )), (( 5 == 5 ) || ( 3 < 6 )) (( 5 == 5 ) && ( 3 > 6 )), (( 5 == 5 ) || ( 3 > 6 )) (( 5 != 5 ) && ( 3 < 6 )), (( 5 != 5 ) || ( 3 < 6 )) (( 5 != 5 ) && ( 3 > 6 )), (( 5 != 5 ) || ( 3 > 6
.7المعامل الشرطً (?) ٌعمل هذا المعامل على تقٌٌم تعبٌر ما وٌعٌد إحدى قٌمتٌن وفقا لتقٌٌم التعبٌر .وله الشكل اآلتً: condition ? result1 : result2 وهو ٌكافا التعلٌمة التالٌة ) if (condition == true ;return result1 else ;return result2 أي :إذا كان الشرط محققا ا فإنّ المعامل سٌعٌد النتٌجة األولى و ّإال سٌعٌد النتٌجة الثانٌة. مثال: ;a = 7, b = 3 ; (a == b) ? return 1 : 2 سٌعٌد العدد 3ألن الشرط غٌر محقق ) 7ال تساوي .(2
44
.8معامل تحوٌل البٌانات ٌسمح لك هذا المعامل بتحوٌل متغٌّر من نوع إلى آخر وهناك عدّة طرق لفعل ذلك واألكثر شهرة منها هو المعامل التالً )type( :أو )type (value مثال: ; Int i ; float pi = 3.14 i = (int)pi ; // pi = 3.14 , i = 3 السطر الثالث من المثال السابق ٌقوم بتحوٌل قٌمة المتغٌّر العشري إلى عدد صحٌح ,و ٌمكن أن ٌكتب بالشكل: ; )i = int(pi
.9المعامل )(sizeof ٌقبل هذا المعامل وسٌطا واحدا إ ّما أن ٌكون نوعا من أنواع البٌانات المؤلوفة أو متغٌّرا بح ّد ذاته ,وهو ٌعٌد حجم الوسٌط بالباٌت.وله الشكل: ; )int a = sizeof(char سٌعٌد هذا المعامل القٌمة 2ألن النوع ٌ charؤخذ 2باٌت فً الذاكرة كما فً الجدول فً الدرس السابق.
أولو ٌّات تنفٌذ المعامالت لٌكن لدٌنا العبارة البرمجٌة التالٌة: ;a=5+8%2 ما هً نتٌجة هذا التعبٌر برأٌك؟ طبعا جوابك هو 7ولكن لماذا؟ ٌخضع ترتٌب تنفٌذ المعامبلت للجدول التالً: األولوٌة 0 3
2
1 5 6 7 8 9 01
العملٌة ::معامل المدى ) ( األقواس sizeof() , *%,/, ++ , -~ ! *& , )(type +,> <= , >= , < , == != , &|,^, && || , ?: = &= , ^= , |= %= , /= , *= , -= , += , ,
جهة األولو ٌّة من الٌسار من الٌسار من الٌسار من الٌمٌن
من الٌسار من الٌسار من الٌسار من الٌمٌن من الٌمٌن من الٌسار
45
مثال:
46
: ما هً قٌمة العبارات التالٌة.2 int a = 0 ; long b = 1, c = 2, d = 3 ; bool e = true , r = true , t = false ; a) a += (b = c = d - 5) ; b) d %= 2 * c / ++b ; c) a = d – ( b += ( c * ( 1 – a ) ) ) ; d) e = !e ; e) r = e || t ; f) t = e && r ; g) e = !( (e && r ) || (e && t ) ) ; : فً كل مرةx حدد أولوٌات العملٌات فً التعابٌر التالٌة ث ّم أوجد قٌمة.3 a) x = 7 + 3 * 6 / 2 – 1 ; b) x = 2 % 2 + 2 * 2 – 2 / 2 ; c) x = ( 3 * 9 * ( 3 + ( 9 * 3 / ( 3 ) ) ) ) ; d) c = 2*b – 3/d + a++; : اكتب ناتج الجمل التالٌة.4 a) b) c) d)
47
cout<< ++a ; cout<< a++ ; cout<< a++ / 2 ; cout<< ++a / 2 ;
الفصل السادس :
إنّ البرنامج لٌس عبارة عن مجموعة من تعلٌمات اإلسناد أو المقارنات أو اإلدخال واإلخراج التً تعلّمناها ح ّتى اآلن ,فنحن وكما تعلم نتحدّث عن البرمجة التً إ ّنما نستخدمها كً تساعدنا فً حل مشاكلنا الٌومٌة ومن األشٌاء المهمّة التً نحتاج إلٌها هً اتخاذ القرارت المناسبة إلجراء عملٌات مع ٌّنة دون أخرى .توفّر C++مجموعة بُنى برمجٌة نسمٌها بنى التحكم ,و البنٌة البرمجٌة هً عبارة عن مجموعة من التعلٌمات ٌفصل بٌن كل تعلٌمتٌن متتالٌتٌن فٌها فاصلة منقوطة ,وتكون هذه المجموعة محصورة بٌن قوسً البنٌة } { .معظم البنى التً سنتعرّ ف علٌها اآلن تحتاج إلى عبارة عا ّمة كوسٌط ٌت ّم تمرٌره إلٌها .فً حال كانت البنٌة تحوي تعلٌمة واحدة فقط فإ ّنها ال تحتاج إلى القوسٌن } { أ ّما إذا كانت البنٌة تحوي أكثر من تعلٌمة فإ ّنها تحتاج إلٌهما.
)1بنٌة الشرط condition structure كثٌرا ما ن ّتخذ قراراتنا باستخدام الشرط فعندما تقول" :إذا حصل هذا الشًء عندها سؤفعل كذا وكذا" .فإ ّنك تستخدم شرطا تبنً على تح ّققه قرارا فً تنفٌذ مجموعة من األشٌاء أو عدم تنفٌذها .لنتعرّ ف كٌف نستطٌع أن نفعل ذلك باستخدام C++ ) if ( condition تعلٌمة واحدة فقط statement ; // أٚ ) if ( condition { أكثر من تعلٌمة statements… // } حٌث أنّ التعلٌمات التً داخل هذه البنٌة ال ٌت ّم تنفٌذها ّإال إذا كان الشرط الذي بٌن القوسٌن )(condition مح ّققا. مثال :نرٌد من المستخدم أن ٌدخل رقما ما فإذا كان (الرقم ٌساوي )011عندها سنطبع العبارة" x is 100 " : ) if ( x == 100 ; " cout << " x is 100 فً هذا المثال لدٌنا تعلٌمة واحدة فقط لذلك لم نستخدم القوسٌن }{ ,و لو أردنا أن نضٌف تعلٌمات أخرى إلى هذه البنٌة عندها ٌجب أن نستخدم القوسٌن }{ أي: ) if ( x == 100 { ; " cout << " x is ; cout << x … statements }
48
هناك نوع آخر من الشرط نستخدمه فً حٌاتنا فكثٌرا ما نقول ":إذا حصل هذا الشًء عندها سؤفعل هذه األشٌاء و إال سؤفعل أشٌاء أخرى ". ) if ( x == 100 ; statement1 else ; statement2 فً المثال السابق نرٌد من المستخدم أن ٌدخل رقما ما فإذا كان (الرقم ٌساوي )011عندها سنطبع العبارة" x is 100 " : و ّإال سنطبع العبارة " x is not 100 " : )if (x == 100 ;"cout << "x is 100 else ;"cout << "x is not 100 الٌزال هناك حالة أخٌرة للشرط وسنحتاجها بكثرة أٌضا وهً من الشكل: ( شرط ) 0عندها ِافعل األشٌاء1 إذا كان و إال إذا كان ( شرط ) 2عندها ِافعل األشٌاء2 . . . وإال ِافعل األشٌاءn
)if (condition 1 { ; statements 1 } )else if (condition 2 ; statement 2 . . else ;statement n
مثال: )if (x > 0 ;"cout << "x is positive )else if (x < 0 ;"cout << "x is negative else ;"cout << "x is 0
49
)2بنى التكرار loops or repetition structures
ٌ شرط ما( أثناء كتابة برامجنا قد نحتاج إلى تكرار مجموعة من التعلٌمات )عددا من المرات أو ح ّتى ٌتح ّقق فعندما ترٌد أن تطبع األرقام من 12إلى 1تنازل ٌّا فما الذي ستصنعه هل ستكتب 12مرّ ات التعلٌمة cout لتخرج كل مرّة رقما أق ّل من سابقه ماذا لو أردت طباعة 1222رقم أو أكثر .إنّ استخدام البنى التكرارٌة سٌسهّل هذا األمر كثٌرا .هناك ثبلثة أشكال من البنى التكرارٌة سنتعرف علٌها تباعا وهً: while ( condition ) statements البنٌة األولى :مادام ) الشرط محققا ا ( نفذ التعلٌمات التالٌة البرنامج التالً ٌستخدم هذه الحلقة لطباعة األرقام من 12إلى 1تنازل ٌّا كما هو موضح: !10, 9, 8, 7, 6, 5, 4, 3, 2, 1, FIRE
// custom countdown using while >#include <iostream ;using namespace std )( int main { ; int n = 10 )while (n>0 { ;" cout<< n << ", ;n-- } ;"!cout<< "FIRE ;return 0 }
بدأ البرنامج من التابع )( ,mainث ّم صرّ حنا عن المتغٌّر nالذي حمل القٌمة ,12ث ّم استخدمنا البنٌة while التً تفحص الشرط n > 0أوالا فإذا كان الشرط محققا فإ ّنها تقوم بما ٌلً: -1تطبع العدد .n -3تنقص العدد nبمقدار .1 -2نهاٌة البنٌة ث ّم العودة للتح ّقق من الشرط مرّ ة أخرى فإذا كان مح ّققا عادت إلى الخطوة .1 و إال سٌنتقل المترجم إلى التعلٌمات التً تقع بعد هذه البنٌة وهً طباعة العبارة !.FIRE ث ّم نهاٌة البرنامج. البنٌة الثانٌة :ن ّفذ التعلٌمات التالٌة مادام ) الشرط محققا ا ( ;)do statements while (condition البرنامج التالً ٌستخدم هذه الحلقة لطباعة األرقام من 12إلى 1تنازل ٌّا كما هو موضح: !10, 9, 8, 7, 6, 5, 4, 3, 2, 1, FIRE
// custom countdown using while >#include <iostream ;using namespace std )(int main { ; int n = 10 do { ;" cout << n << ", ;n-- ;)} while (n>0 ;"!cout << "FIRE ;return 0 }
4:
بدأ البرنامج من التابع )( ,mainث ّم صرّ حنا عن المتغٌّر nالذي حمل القٌمة ,12ث ّم استخدمنا البنٌة doالتً تنفذ التعلٌمات أوالا وهً تقوم باآلتً: .1تطبع العدد .n .3تنقص العدد nبمقدار .1 .2نهاٌة البنٌة ث ّم التحقق من الشرط ّ ّ محققا فإنها تعود إلى الخطوة .1 فإذا كان الشرط سٌنتقل المترجم إلى خارج هذه البنٌة وٌطبع عبارة !.FIRE و إال ث ّم نهاٌة البرنامج.
تنبٌهات حول البنٌتٌن السابقتٌن ٌ -1جب أن تضع شرطا قاببل للتحقق كً تضمن انتهاء الحلقة )البنٌة( التكرارٌة ألنّ عدم تحقق الشرط ٌعنً الدخول فً حلقة ال نهابٌة وبالتالً لن ٌتوقف البرنامج عن العمل. فمثبل لو وضعنا ; n++بدال من ; n--فً أحد المثالٌن السابقٌن فإنّ الحلقة لن تنتهً أبدا. -3هاتان البنٌتان ال تمتلكان عدّادات زٌادة أو نقصان فً داخلهما لذلك فهما تقببلن الشروط المنطقٌة و العددٌة وٌجب علٌك أن تجد طرٌقة تستطٌع من خبللها أن تعرف فٌما إذا تحقّق الشرط )المنطقً أو العددي( أوّ ال ,فً المثال السابق استخدمنا المتغٌّر nلهذه المهمة الذي أخذ ٌتناقص مع كل تكرار ح ّتى تحقق شرط . التوقف ّ ّ ا -2البنٌة whileتقوم باختبار الشرط ّأوال ث ّم تنفذ التعلٌمات التً بداخلها لو كان الشرط محققا .أي أنه قد محقق .بٌنما تعمل البنٌة doبعكس غٌر ال ٌت ّم تنفٌذ تعلٌمات هذه البنٌة وال مرّ ة فً حال كان الشرط َ ٍ مر اة أولى ث ّم تتح ّقق من الشرط فإذا تح ّقق أعادت تكرار العملٌات التً أختها فهً تن ّفذ تعلٌمات بنٌتها ّ بداخلها و إال خرجت من البنٌة و تابعت البرنامج. البنٌة الثالثة: )for (initialization ; condition ; increase ;statement
تتمتع هذه البنٌة بشهرة كبٌرة ألنها من أسهل و أكثر الحلقات التكرارٌة استخداما ,فهً تعمل على تكرار التعلٌمات التً بداخلها ابتداء من قٌمة مع ٌّنة وح ّتى قٌمة االنتهاء التً ٌجب أن تكون محدّدة ,وهً تحتوي على عدّاد بداخلها ٌستطٌع المبرمج أن ٌتح ّكم بمقدار زٌادته أو نقصانه. البرنامج التالً ٌستخدم هذه الحلقة لطباعة األرقام من 12إلى 1تنازل ٌّا كما هو موضح: !10, 9, 8, 7, 6, 5, 4, 3, 2, 1, FIRE
// custom countdown using for >#include <iostream ;using namespace std )( int main { ) for ( int n=10 ; n>0 ; n-- { ;" cout << n << ", } ;"!cout << "Fire ;return 0 }
51
ٌمكن أن تض ّم هذه الحلقة عدّادٌن بنفس الوقت فتؤخ َذ الشكل التالً:
Initialization Condition
)
; n++ , i--
; n!=i
n=0 , i=100
Increase
( for {
// whatever here... } ْ الحلقة ستتوقف تبدأ هذه الحلقة بالقٌم االبتدابٌة التالٌة n = 0و i = 100وتستمرّ مادام n != iأي أنّ بعد 52تكرارا ألنّ i = n = 50
كما ٌمكن أن تكتب هذه الحلقة باألشكال التالٌة أٌضا: لم نعطً العداد قٌمة ابتدابٌة ولم نحدد مقدار خطوة الزٌادة //
);for (;n<10
لم نعطً العداد قٌمة ابتدابٌة فقط for (;n<10;n++) // حلقة ال نهابٌة ٌمكن الخروج منها باستخدام التعلٌمة ; // break
); ;(for
ٌمكن أن نستخدم الحالة األخٌرة عندما ال نستطٌع أن نعرف قٌمة التوقف أو عندما نرغب باستخدام شرط منطقً بدال من العدّاد كما فً المثال التالً:
مثال: البرنامج التالً ٌقوم بقراءة رقم من لوحة المفاتٌح وطباعته على الشاشة وٌكرّ ر هذه العملٌة حتى ٌدخل المستخدم الرقم 2 Enter number (0 to end): 5 You entered: 5 Enter number (0 to end): 0 You entered: 0
// number echoer >#include <iostream ;using namespace std )( int main { ;unsigned long n ;" cout << "Enter number (0 to end): ;cin >> n ;"cout << "You entered: " << n << "\n )while(n != 0 { ;" cout << "Enter number (0 to end): ;cin >> n ;"cout << "You entered: " <<n<< "\n } ;return 0 }
52
// number echoer #include <iostream> using namespace std; int main () { unsigned long n; do { cout << "Enter number (0 to end): "; cin >> n; cout << "You entered: " << n<< "\n"; } while (n != 0); return 0; }
Enter number (0 to end): 5 You entered: 5 Enter number (0 to end): 0 You entered: 0
// number echoer #include <iostream> using namespace std; int main () { unsigned long n; for (; ;) { cout << "Enter number (0 to end): "; cin >> n; cout << "You entered: " << n << "\n"; if (n== 0) break; } return 0; }
Enter number (0 to end): 5 You entered: 5 Enter number (0 to end): 0 You entered: 0
تستخدم هذه التعلٌمة للخروج من البنٌة التً ُكتِبت فٌها كما فً الحالة الثالثة من:break ) التعلٌمة3 (n == 0) فنحن نرٌد أن نخرج من الحلقة)البنٌة(التكرارٌة بمجرّ د أن ٌتح ّقق الشرط,المثال السابق ً تستخدم هذه التعلٌمة عندما نرغب بؤن ٌتجاهل البرنامج التعلٌمات التً تل:continue ) التعلٌمة4 . والعودة إلى بداٌة البنٌة البرمجٌة التً كتبت فٌها هذه التعلٌمةcontinue التعلٌمة :ً باستخدام هذه التعلٌمة فسنكتب اآلت5 ماعدا الرقم12 و1 فلو أردنا أن نكتب برنامجا ٌطبع األعداد بٌن #include <iostream> using namespace std; int main() { for (int n=10; n>0;n--) { if (n==5) continue; cout << n << ", "; } cout << "FIRE!\n"; return 0; }
53
10, 9, 8, 7, 6, 4, 3, 2, 1, FIRE!
البداٌة من التابع )(ٌ .mainدخل المترجم الحلقة التكرارٌة وعندها تكون قٌمة العدّاد n = 12ث ّم ٌختبر الشرط ) (n == 5وبالطبع لن ٌكون الشرط مح ّققا ألنّ 10 != 5وعندها ٌتجاهل التعلٌمة الموجودة داخل بنٌة الشرط ifث ّم ٌنتقل إلى التعلٌمة التالٌة وهً تعلٌمة طباعة العدد nوبعدها تنتهً الحلقة للمرّ ة األولى فٌعود المترجم إلى معامل النقصان فً الحلقة وٌغٌر قٌمة العداد nبحسب قٌمة النقصان المطلوبة )فً حالتنا (1ث ّم ٌختبر الشرط n>0فإن كان محققا فسٌعود إلى داخل الحلقة مرّ ة أخرى وٌستمر فً هذه العملٌات حتى تصبح قٌمة n = 5عندها سٌختبرالشرط n == 5والذي أصبح محققا لذلك سٌن ّفذ التعلٌمة الموجودة داخل تعلٌمة الشرط وهً التعلٌمة continueوالتً ستجبر المترجم على تجاهل التعلٌمات التً تلٌها مما ٌعنً تجاهل التعلٌمة ;" cout << n << ",والعودة إلى بداٌة الحلقة إلنقاص الع ّداد واختبار الشرط ث ّم الدخول فً الحلقة من جدٌد وهكذا حتى نهاٌة الحلقة. )5التعلٌمة :gotoبهذه التعلٌمة تستطٌع إجبار المترجم على القفز من السطر الذي هو فٌه إلى السطر الذي ترٌده لٌكمل التنفٌذ من المكان الذي أرسلته إلٌه .الستخدام هذه التعلٌمة نحتاج إلى الفتة label الستعمالها كدلٌل على السطر الذي سنرسل المترجم إلٌه ,وهذه البلفتة ٌجب أن تتبع بالنقطتٌن ) .( : مثال: !10, 9, 8, 7, 6, 5, 4, 3, 2, 1, FIRE
// goto loop example >#include <iostream ;using namespace std )( int main { ;int n=10 loop:// goto label ;" cout << n << ", ;n-- )if (n>0 ;goto loop ;"cout << "FIRE!\n ;return 0 }
فً المثال السابق استطعنا أن نطبع األعداد من 12إلى 1دون استخدام حلقات تكرارٌة وذلك باستخدام .goto كالمعتاد بدأ البرنامج من التابع )( ,mainث ّم صرّ حنا عن المتغٌّر nالذي أخذ القٌمة 12ث ّم بعد ذلك صرّ حنا عن البلفتة loop:وبعدها طبعنا قٌمة nث ّم أنقصناها بمقدار 1بعد ذلك وضعنا شرطا لنعرف إذا ما كانت n>0أو ال فإذا كانت n > 0عندها سنعٌد المترجم إلى السطر الذي ٌحوي البلفتة loop:لٌعٌد العملٌات السابقة كلّها حتى تصبح n = 0عندها لن ٌرجع المترجم إلى البلفتة وسٌكمل البرنامج لٌطبع العبارة ! FIREث ّم ٌنتهً البرنامج. )6التعلٌمة :switchتشبه هذه التعلٌمة فً وظٌفتها التعلٌمة ifفهً تختبر قٌمة المتغٌّر الذي ٌت ّم تمرٌره لها كوسٌط ث ّم تحدد العمل الذي ستقوم به من خبلل قٌمة المتغٌّر. ولها الشكل التالً: )switch(variable { case value1: ;statements ;break …//other cases here default: //optional ;statements ;break } 54
. نرٌد برنامجا ٌخبر المستخدم عن الٌوم الذي ٌقابل الرقم الذي أدخله المستخدم:مثال ّ (7 - 1 ونخزنه فً متغٌّر عددي صحٌح و موجب)ألن األرقام هً بٌن أوال ٌجب أن نقرأ الرقم ... وهكذاFriday ٌقابل ٌوم الجمعة1 ثانٌا سنختبر قٌمة المتغٌّر ث ّم نقابله بالنصّ المناسب فالرقم .ثالثا سنطبع اسم الٌوم المناسب على شاشة الخرج // switch #include<iostream> using namespace std; int main() { unsigned short dnum ; cout<< "Enter number of day(1-7): "; cin>> dnum; cout<< "\n"; switch(dnum){ case 1: // if dnum = 1 cout << "the day is Friday"; break; case 2: // if dnum = 2 cout << "the day is Saturday"; break; case 3: // if dnum = 3 cout << "the day is Sunday"; break; case 4: // if dnum = 4 cout << "the day is Monday"; break; case 5: // if dnum = 5 cout << "the day is Tuesday"; break; case 6: // if dnum = 6 cout << "the day is Wednesday"; break; case 7: // if dnum = 7 cout << "the day is Thursday"; break; default: // if dnum < 1 or dnum> 7 cout << "Sorry we're closed "; break; } cout<< "\n"; return 0; }
55
// if #include<iostream> using namespace std; int main() { unsigned short dnum ; cout<< "Enter number of day(1-7): "; cin>> dnum; cout<< "\n"; if(dnum == 1) cout << "the day is Friday"; else if(dnum == 2) cout << "the day is Saturday"; else if(dnum == 3) cout << "the day is Sunday"; else if(dnum == 4) cout << "the day is Monday"; else if(dnum == 5) cout << "the day is Tuesday"; else if(dnum == 6) cout << "the day is Tuesday"; else if(dnum == 7) cout << "the day is Thursday"; else cout << "Sorry we're closed "; cout<<'\n'; return 0; }
لنشرح ما حصل فً التعلٌمة switch ّ وخز ّناه فً كما عوّ دتنا c++بدأ البرنامج من التابع )( mainث ّم صرّحنا عن المتغٌّر ,dnumث ّم قرأنا الرقم المتغٌّر ,dnumواآلن جاء دور التعلٌمة switchالتً أخذت المتغٌّر dnumوسٌطا .بعد ذلك قمنا بذكر الحاالت التً ٌمكن للمتغٌّر أن ٌحملها وهً األرقام } {1,2,..,7وذكرنا كل عنصر منها لوحده بعد الكلمة caseث ّم وضعنا التعلٌمة التً تناسب كل حالة على حدة وفً نهاٌة كل حالة كتبنا التعلٌمة breakالتً شرحناها سابقا والتً لها أهمٌّة كبٌرة فً التعلٌمة switchفعندما ٌقارن المترجم قٌمة المتغٌّر الوسٌط مع الحالة األولى و تكون القٌمتٌن متساوٌتٌن عندها سٌنفذ التعلٌمات الخاصة بهذه الحالة وعندما سٌنتهً منها نرٌد منه أن ٌخرج من التعلٌمة ّ switch وأال ٌختبر باقً الحاالت لذلك وضعنا التعلٌمة breakولو لم نضعها الخبتر المترجم كل الحاالت الباقٌة وهذا ٌعنً مضٌعة للوقت وبطؤ للبرنامج ال نرٌده أن ٌحصل طبعا .أمّا التعلٌمة defaultفهً تخصّ باقً االحتماالت الممكنة إذ قد ٌدخل المستخدم رقما غٌر األرقام المذكورة لذلك نرٌد من البرنامج أن ٌخبر المستخدم أ ّنه أدخل رقما خاطبا .جرّ ب البرنامجٌن ,وستجد أن لهما نفس الناتج تماما كما فً الشكل: Enter number of day: 5 the day is Tuesday
باستخدام إحدى البنى التكرارٌة أو باستخدام التعلٌمة gotoعدّل البرنامج السابق لٌكرّ ر اإلدخال ح ّتى ٌدخل المستخدم رقما من خارج المجال 1إلى 7حٌث ٌخرج من البرنامج.
56
)7
الحلقات المتداخلة :nested loopsقلنا عند الحدٌث عن البنى التكرارٌة" :إ ّنها تم ّكننا من تكرار مجموعة من التعلٌمات عددا من المرّ ات" .أي أ ّنه ٌمكننا أن نطبع الشكل التالً باستخدام حلقة تكرارٌة كما بٌّنا من قبل: 1 2 3 4 5 1 2 3 4 5
>#include <iostream ;using namespace std )( int main { )for(int j = 1 ; j<=5 ; j++ ;" " << cout << j ;return 0 }
لكن ماذا لو أردنا أن نطبع الشكل التالً و الذي ٌمثل عناصر مصفوفة ثنابٌة األبعاد. 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 ٌمكن فهم هذا الشكل على أ ّنه طباعة األعداد من 1إلى 5ثبلث مرّ ات متتالٌة على ثبلثة أسطر متتالٌة أٌضا أي أ ّننا سنقوم بتكرار عمل الحلقة السابقة ثبلث مرّات كما فً الشكل التالً: 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
// nested loop >#include <iostream ;using namespace std )( int main { {)for( int i = 1 ; i<=3 ; i++ )for(int j = 1 ; j<=5 ; j++ ;" " << cout << j ;"cout<<"\n } ;return 0 }
تبدأ الحلقة األولى عندما i = 1وبما أنّ 1<3سٌ ّتجه المترجم إلى داخل الحلقة األولى لٌن ّفذ ما فٌها من تعلٌمات فٌجد أنّ أول تعلٌمة أما َمه هً الحلقة الثانٌة التً تبدأ من j = 1وتطبع األرقام من 1إلى 5على نفس السطر حٌث ٌعلق المترجم فً هذه الحلقة ح ّتى ٌنتهً منها عندما ,j = 6ث ّم ٌ ّتجه المترجم إلى التعلٌمة الثانٌة فً الحلقة األولى وهً ;" cout<<"\nوالتً تعنً ِابدأ سطرا جدٌدا ,ث ّم ٌنتهً التكرار األول لهذه الحلقة ,وتت ّم زٌادة العدّاد iبمقدار 1لٌصبح i = 2وٌت ّم اختبار الشرط مرّ ة أخرى وبما أنّ 2<3فإنّ المترجم سٌعود وٌدخل الحلقة األولى لٌقوم بنفس الخطوات السابقة ,فٌعٌد قٌمة jإلى 1لٌعلق مرّ ة أخرى فً الحلقة الثانٌة فٌقوم بطباعة األرقام من جدٌد على السطر الجدٌد الذي جاء من التعلٌمة ;" ,cout<<"\nوعندما ٌنتهً من الحلقة الثانٌة ٌكمل الحلقة األولى فٌطبع سطرا جدٌدا ,ث ّم ٌكرّ ر ذلك مرّ ة أخٌرة حٌث تكون i = 3 وبعدها تصبح i = 4م ّما ٌعنً أنّ المترجم سٌغادر الحلقة دون أن ٌنفذها مرّ ة رابعة وعندها نحصل على الشكل السابق.
57
.ًاكتب برنامجا ٌطبع الشكل التال:مثال * * * * *
* * * * * * * * * *
// nested loop #include <iostream> using namespace std; int main () { for( int i = 1 ; i<=5 ; i++) { for(int j = 1 ; j<=i ; j++) cout << "* "; /* for(int j = 1 ; j<=5 ; j++) if(j<=i) cout << "* "; */
* * * * *
* * * * * * * * * *
cout<<"\n"; } return 0; }
for مع الحلقةwhile المثال السابق باستخدام الحلقة // nested loop #include <iostream> using namespace std; int main () { int j = 1; for( int i = 1 ; i<=5 ; i++) { j = 1 ; while( j<=i ) { cout <<"* " ; j++; } cout<<"\n" ; } return 0; }
58
* * * * *
* * * * * * * * * *
.1اكتب برنامجا ٌطلب من المستخدم أن ٌدخل رقما ث ّم عملٌّة حسابٌّة من العملٌّات األربع المعروفة ث ّم ٌطلب آخر ث ّم ٌظهر النتٌجة وفقا للعملٌّة التً أدخلها المستخدم )باستخدام .(switch رقما َ
.0
.2
الخوارزمٌة (aاقرأ الرقم األول .n1 (bاقرأ العملٌة .op (cاقرأ الرقم الثانً .n2 (dافحص العملٌة op ' op = '+اطبع المجموع إذا كانت وإال إذا كانت '–' = opاطبع الفرق وإال إذا كانت '*' = opاطبع الجداء وإال إذا كانت 'op = '/ إذا كان الرقم الثانً ال ٌساوي الصفر اطبع القسمة و ّإال اطبع عبارة . Infinite الشٌفرة >#include<iostream ;using namespace std )(int main { ;float n1 , n2 ;'char op = '+ ;cout<<"Enter n1:"; cin>> n1 ;" cout<<"\nEnter Operator of {+,-,/,*}: ;cin>>op ;cout<<"\nEnter n2: "; cin>> n2 )switch(op {case '+': ;cout<< n1<<op<<n2<<" = "<<n1+n2 ;break case '-': ;cout<< n1<<op<<n2<<" = "<<n1-n2 ;break case '*': ;cout<< n1<<op<<n2<<" = "<<n1*n2 ;break case '/': )if(n2 != 0 ;cout<< n1<<op<<n2<<" = "<<n1/n2 ;"else cout<<"Infinite ;break } ;return 0 }
59
.3اكتب برنامجا ٌحسب أصغر األعداد التً ٌدخلها المستخدم وعددها ٌ nحدّده المستخدم.
.0الخوارزمٌة (aاقرأ .n (bاقرأ الرقم األول . (cاعتبر أنّ أصغر عدد هو الرقم األول )وذلك لكً نقارن كل األعداد التً سنقرأها به ) ( minفإن وجدنا )
( أصغر منه اعتبرناه هو األصغر (.
(dمن أجل i = 2حتى ) i = nقرأنا الرقم األول سابقا لذلك بدأنا من (3
اقرأ إذا كان (eاطبع أصغر عدد min .2الشٌفرة
فاعتبر أن
>#include<iostream ;using namespace std )(int main { ;int n, a, min ;" cout<<"Enter n: ;cin>>n ;" cout<<"\nEnter number 1: ;cin>>a ;min = a )for(int i =2 ; i <=n;i++ { ;" cout<<"\nEnter number "<<i<<": ;cin>>a )if(a<min ;min = a } ;cout<<"\nmin = "<< min << endl ;return 0 }
.2اكتب برنامجا ٌقرأ اسم طالب وعدد العبلمات التً ٌرغب بحساب المتوسط الحسابً لها ث ّم ٌقرأ ك ّل عبلمة منها وفً النهاٌة ٌطبع اسم الطالب ومتوسطه الحسابً فً ك ّل المواد.
.0الخوارزمٌة (aاقرأ اسم الطالب ثم عدد العبلمات. (bمن أجل i = 1حتى i = nبزٌادة قدرها 1 اِقرأ العبلمة رقم i أضف العبلمة رقم iإلى المجموع (cاطبع اسم الطالب ثم المتوسط الحسابً )المجموع ÷ .(n
5:
.2الشٌفرة >#include<iostream >#include<string ;using namespace std )(void main ;{ string name ;int n,mark,i = 0,sum = 0 //important to initial sum and i to 0 here (it's local var). ;" cout<< "Enter student name: ;cin>>name ;cout<< "Enter number of marks: "; cin>>n )while(i++ < n { ;" cout<< "Enter mark ("<<i<<") [between 0 and 100]: ;cin>> mark ;sum += mark }; // you can do that ;'cout<< name << " Average = " << (float)sum/n <<'\n }
.6اكتب برنامجا لحساب السلسلة التالٌة حٌث تدخل nمن لوحة المفاتٌح
.0الخوارزمٌة (aاقرأ .n (bمن أجل القٌم بٌن الـ i=1حتى i=n
فإن
المجموع = aالمجموع + a (cاطبع المجموع. .2الشٌفرة >#include<iostream ;using namespace std )(int main { ; int n float a = 0.0f ;//Initial a to 0 where f means float value ;" cout<<"Enter n: ;cin>>n )for(int i=1;i<=n;i++ ;a+=1.0f/i;//like a = a + (float)1/i ;cout<< a << endl ;return 0 } ّ المخزنة فً المتغٌّر aهً من النوع مالحظة :التعلٌمة ; float a = 0.0fتعنً أنّ القٌمة
العشري و لٌس الصحٌح .وكذلك األمر فً التعلٌمة ; a+=1.0f/iوكان بإمكاننا أن نكتبها كالتالً: ; a += (float)1 / i
ألنّ ناتج عمل ٌّة القسمة الموجودة على ٌمٌن المساوة السابقة لٌس بالضرورة عددا صحٌحا فمثبل العدد 1/2 = 0.5وهو عشريّ لذلك قمنا بتعرٌف المجموع على أ ّنه عشريّ ث ّم قمنا بتحوٌل الطرف األٌمن من المساواة إلى النوع العشريّ لنضمن عدم ضٌاع البٌانات ألنّ قسمة عددٌن صحٌحٌن هً عدد صحٌح فً .c++ولو لم نفعل ذلك فإن ناتج التعلٌمة سٌكون كاآلتً: 61
a +=
1 / i ;
a = 0.0 + 1 / 1 = 0.0 + 1 = 1.0 a = 1.0 + 1 / 2 = 1.0 + 0 = 1.0
عندهاi = 1 عندهاi = 2 ... عندهاi = n
a = 1.0 + 1 / n = 1.0 + 0 = 1.0
اكتب برنامجا ٌحسب السلسلة التالٌة من أجل أي عدد ٌدخله المستخدم.5
=
الخوارزمٌة.0 .n ( اقرأa ّ فإنi=n حتىi=0 ( من أجل القٌم بٌن الـb : =i! احسب * j فإنj=i حتىj=1 من أجل+ e = المجموعe المجموع
.( اطبع المجموعc الشٌفرة.2 #include<iostream> using namespace std; int main() { int n; double e = 0.0f; //Initial a to 0 where f means float value double fact = 1; cout<<"Enter n: "; cin>>n; for(int i=0;i<n;i++) { fact = 1; //initial fact to 1 for each calculation of i! for(int j = 1; j<=i;j++) fact *= j; e += 1.0f/fact; //like e = e + (float)1/i; } cout<< e << endl; return 0; }
62
مالحظةٌ :جب علٌك أن تقوم بتبدبة متغٌّرات المجامٌع والجداءات إلى القٌمة الحٌادٌّة فً العملٌّة فمثبل المتغٌّر ّ e ٌمثل مجموع السلسلة ونعلم أنّ الجمع ٌؤخذ 2كقٌمة حٌادٌّة أي أنّ إضافة 2إلى المجموع لن ٌغٌّر من النتٌجة شٌبا. أمّا المتغٌّر factفهو ّ ٌمثل جداءات أي أنّ القٌمة الحٌادٌّة هً 1ألنّ ضربها بؤيّ عدد لن ٌغٌّر من النتٌجة شٌبا .و لو جعلناها 2فإنّ القٌمة التً سنحصل علٌها من أجل المتغٌّر factهً 2ألنّ : fact = 0وهذا ٌعنً أنّ ناتج التعلٌمة التالٌة هو كاآلتً: ; fact = 0
;fact = 0 * j
;fact = fact * j
.4اكتب برنامجا ٌحسب السلسلة التالٌة من أجل أي عددٌن ٌ x,nدخلهما المستخدم.
.0الخوارزمٌة (aاقرأ .x,n (bمن أجل القٌم بٌن الـ i=0حتى i=nفإن إلى (1 )كل مرة نعٌد قٌمة : احسب !=i من أجل j=1حتى j=iفإن = * j
المجموع
= المجموع
+
(cاطبع المجموع. .2الشٌفرة >#include<iostream عند استخدام التوابع الرٌاضٌة مثل #include<cmath> // pow ;using namespace std )(int main { ; int n,x double e = 0.0f ;//Initial a to 0 where f means float value ;double fact = 1 ;" cout<<"Enter n,x: ;cin>>n>>x )for(int i=0;i<n;i++ { !fact = 1;//initial fact to 1 for each calculation of i )for(int j = 1; j<=i;j++ ;fact *= j ;e += pow(x,i)/fact } ;cout<< e << endl ;return 0 }
63
.7اكتب برنامجا لحساب العبلقتٌن التالٌتبن:
∑
∑
̅
.0الخوارزمٌة (aاقرأ .n (bمن أجل القٌم بٌن الـ i=1حتى i=n اقرأ + = المجموع المجموع المتو ّسط الحسابً لؤلعداد = المجموع ÷ .nأي (cاطبع المتوسّط الحسابً. .2الشٌفرة >#include<iostream ;using namespace std )(int main { ;float sum =0 , average=0 , a=0 ;int n ;" cout<<"Enter n: ;cin>>n )for(int i =1 ; i<=n;i++ { ;" cout<<"Enter a"<<i<<" : ;cin>>a ;sum += a } ;average = sum / n ;cout<<"\nAverage = "<<average ;return 0 }
.0الخوارزمٌة (aاقرأ .n (bمن أجل القٌم بٌن i = 1حتى i = n + = المجموع المجموع (cاطبع المجموع.
64
.2الشٌفرة >#include<iostream ;using namespace std )(int main { ;float sum =0 ;int n ;" cout<<"Enter n: ;cin>>n )for(int i =1 ; i<=n;i++ ;sum += i*i*i ;cout<<"\nSum = "<<sum ;return 0 }
.8اكتب برنامجا إلٌجاد جذور معادلة من الدرجة الثانٌة معتمدا على المعلومات التالٌة: √ √
√
{
.0الخوارزمٌة (1اقرأ a,b,c a (3أ( إذا كان 0 b إذا كان 0c إذا كان 0 √ إذا كان <2فإن: √ و ّإال إذا كان =2
√ فإن:
و ّإال اطبع المعادلة مستحٌلة الحل. أو و ّإال) (c=0فإنّ :إما -
و ّإال) (b=0فإنّ
فإذا كان فإنّ √ و إال
فاطبع المعادلة مستحٌلة الحل.
ب( و إال)(a=0
إذا كان 0
bفإنّ
.
وإال اطبع .it's not equation
65
الشٌفرة.2 #include<iostream> #include<cmath> // or <math.h> using namespace std; int main() { float a , b , c; float delta=0.0 , x1=0.0 , x2=.0; float dsqrt=.0; cout<<"Enter a , b , c:"; cin>>a>>b>>c; cout<<"\n"; if(a!=0) //1 { if(b!=0) //2 { if(c!=0) //3 { delta =((b*b) - (4*a*c)); cout<<"delta = "<<delta<<"\n"; if(delta > 0) //4 { x1 = (float)(-1*b + sqrt(delta)) / 2*a; x2 = (float)(-1*b - sqrt(delta)) / 2*a; cout<<"x1 = "<< x1<<"\nx2 = "<< x2 << endl; } else if(delta == 0) { x1 = x2 = (float)-1*b / 2*a ; cout<<"x1 = x2 = "<<x1<<" Doublicated root!\n"; } else cout<<"Impossible in R\n"; } else { x1 = 0; x2 = (float)-1*b/a; cout<<"Either x = "<<x1<<"\nOr x = "<<x2<<endl; } } else { float t = (float)-1*c/a; if(t>=0) cout<<"x = "<<sqrt(t)<<endl; else cout<<" Impossible in R\n"; } } else{ if(b!= 0) cout<<"x = "<< (float) -c/b<<endl; else cout<<"it\'s not equation.\n"; } return 0; }
66
.1اكتب الشٌفرة الموافقة للخوارزمٌّة التالٌة) :باستخدام التعلٌمة (if
.iأدخل المعدّل .iiإذا كان المعدّل أكبر من 89و أصغر أو ٌساوي 122اطبع Excellent .iiiإذا كان المعدّل أكبر من 79و أصغرأو ٌساوي 89اطبع Very Good .ivإذا كان المع ّدل أكبر من 49و أصغرأو ٌساوي 79اطبع Good .vإذا كان المعدّل أكبر من 59و أصغرأو ٌساوي 49اطبع Passed وإال اطبع failed .vi .3صحّ ح البرامج التالٌة:
* * * * * * * * * *
) a) while ( c <= 5 { ;product *= c ;++c ) b) if ( gender == 1 ; "cout<< "Woman ;else ;"cout<<"man ) c) while ( z >= 0 ;sum += z )d // nested loop >#include <iostream ;using namespace std )( int main { ;int j = 1 )for( int i = 1 ; i<=3 ; i++ { ) while( j<i { ; " *"<< cout ;j++ } } ;return 0 }
* * * * *
.2اكتب برنامجا ٌقرأ ثبلثة أعداد ث ّم ٌر ّتبها تصاعدٌّا. .6اكتب برنامجا لك ّل شكل من األشكال التالٌة: 6 6 7 8 9
3 4 5 4 5 6 7 8
5 3 4 5 6 4 5 6 5 6 6
4 6 6 7 6 7 8 6 7 8 9
3 3 4 5 6 5 6 7 7 8 9
2 3 4 5 5 6 7 6 7 8 9
1 6 7 8 9
5 6 7 8
4 5 6 7
3 4 5 6
.5اكتب برنامجا ٌقرأ عددا ث ّم ٌحدد فٌما إذا كان ٌقبل القسمة على 12أو ال. .4اكتب برنامجا لحساب العبلقة التالٌة:
67
.7اكتب برنامجا لحساب وطباعة مجموع األعداد الزوجٌة القابلة للقسمة على 3ما بٌن 1و .99 .8اكتب برنامجا لحساب المضاعف المشترك األصغر LCMلعددٌن مدخلٌن من لوحة المفاتٌح. بطرٌقتٌن مختلفتٌن. .9اكتب برنامجا لحساب العبلقة التالٌة .12اكتب برنامجا ٌطلب من المستخدم أن ٌدخل حرفا ث ّم عددا ,ث ّم ٌقوم البرنامج بطباعة مثلث قابم ومتساوي الساقٌن من هذا الحرف وطول ساقه هو الرقم المدخل سابقا. .11اكتب برنامجا ٌطلب من المستخدم إدخال عددٌن ث ّم ٌقوم بتقسٌم األوّ ل على الثانً )إذا كان العدد الثانً صفرا فإن البرنامج ٌطلب من المستخدم أن ٌعٌد إدخال الرقم الثانً من جدٌد( ,ث ّم ٌخٌر المستخدم بٌن إجراء عملٌة والخروج من البرنامج )و ذلك بإدخال الحرف .(e جدٌدة )وذلك بإدخال الحرف (n ِ .13اكتب برنامجا ٌطبع جمٌع قواسم عدد مدخل من لوحة المفاتٌح.
68
الفصل السابع :
لعلّك تذكر برنامجك األوّ ل فً هذا الكتاب Hello Worldقلنا حٌنها" :إنّ النقطة األولى لبداٌة البرنامج هً التابع )( ."mainلكن ما هو التابع ولماذا نستخدمه؟ التابع :هو بنٌة برمجٌة ٌت ّم تنفٌذها عند استدعابه من أي نقطة فً البرنامج. ونستخدم التوابع أل ّنها تو ّفر الكثٌر من المزاٌا ومنها: -2تختصر من طول البرنامج و تو ّفر الوقت ,فبدال من إعادة كتابة ماسٌقوم به تابع ما ع ّدة مرّ ات فإ ّننا نكتبه مرّ ة واحدة فً تابع ث ّم نستدعً هذا التابع كلّما دعت إلٌه الحاجة. -3تسهل قراءة البرنامج وتت ّبع األخطاء ,أل ّنه من غٌر الج ٌّد أن تكتب برنامجك كلّه داخل التابع )(main فٌصبح متشابكا وتصعب قراء ُته. -4تصوّ ر أ ّنك كتبت برنامجا استخدمت فٌه مجموعة من التعلٌمات ع ّدة مرّ ات ث ّم قرّ رت أن تح ِّسن من أداء هذه التعلٌمات أو أن تصحِّ ح خطؤ ما فٌها ,فهل ستقوم بهذا التصحٌح من أجل كل مرّ ة كتبت فٌها تلك التعلٌمات .ماذا لو استخدمت تابعا ٌقوم بهذه العملٌات ث ّم استدعٌته تلك المرّ ات العدٌدة؟ عندها سٌكون كافٌا أن تعدّل التابع مرّ ة واحدة فقط لٌسري هذا التعدٌل فً برنامجك كلّه دون عناء ٌذكر. وتشبه التوابع البرمجٌة الدوال الرٌاض ٌّة فً عملها إلى ح ٍّد ما ,فهً تقوم بمجموعة من العملٌات ث ّم تعٌد قٌمة وحٌدة تدعى قٌمة التابع. كٌف نصرح عن التوابع؟ ٌتم التصرٌح عن التوابع وفقا للقاعدة التالٌة: )return_value_type function_name( argument1, argument2,.. . { ;Statements ... ;return function_value } حٌث أن: return_value_type نوع القٌمة التً سٌعٌدها التابع. function_name اسم التابع ,وبه ٌمكننا استدعاء التابع. َ ُعالجها وٌستخر َج القٌمة المطلوبة ,وهذه arguments الوسطاء التً ٌت ّم تمرٌرها إلى التابع لٌ َ الوسطاء اختٌارٌّة أي أ ّنه ٌمكن االستغناء عنها كلِّها ,ولكن ٌجب اإلبقاء على األقواس )( بعد اسم ٌسبق اس َمه نو ُع البٌانات التً ٌحملها كما لو كان متغٌّراّ .إال أ ّنه متغٌّر التابع ,وكل وسٌط ٌجب أن ِ شكلًّ فقط ,وعند استدعاء التابع سٌت ّم استبدال الوسطاء بمتغٌّرات أو ثوابت من نفس النوعٌ .فصل بٌن كل وسٌطٌن متتابعٌن فاصلة من الشكل ) .( , statements هً التعلٌمات التً تشكل جسم التابع .قد تكون مإلّفة من تعلٌمة واحدة أو أكثر وفً كلتً الحالتٌن ٌجب أن توضع بٌن القوسٌن } { .تقوم هذه التعلٌمات بإٌجاد قٌمة التابع المطلوبة. return function_value هذه التعلٌمة تعٌد القٌمة التً حُسِ َب ْ ت فً جسم التابع ,وهذه القٌمة وحٌدة.
69
تابع لنا فً هذا الكتاب: و اآلن لنكتب أوّ َل ٍ The result is 8
// function example >#include <iostream ;using namespace std )int addition (int a, int b { ;int r = a + b ;)return (r } )( int main { ;int z ;)z = addition (5,3 ;cout << "The result is " << z ;return 0 }
أذ ُك ُر أ ّننا قلنا فً درسنا األول" :إنّ البرنامج ٌبدأ من التابع )( mainدابما" .لذلك سنبدأ من هناك. تستطٌع أن ترى كٌف أن التابع )( mainبدأ بالتصرٌح عن المتغٌّر zمن النوع الصحٌح ,وبعد ذلك نجد التعلٌمة ; )z = addition(5,3 إنّ التعلٌمة السابقة ّ تمثل استدعاء للتابع additionولو أ ّننا انتبهنا لوجدنا تشابها كبٌرا بٌن استدعاء التابع و التصرٌح عنه كما فً الشكل: )int addition(int a,int b ;)
5 ,
3
(z = adition
حٌث ٌت ّم استبدال الوسٌطٌن الشكلٌٌن a, bبالقٌمتٌن 5, 3على الترتٌب ث ّم ٌتوجّه المترجم إلى التابع addition تاركا التعلٌمات التً لم ّ ٌنفذها بع ُد من التابع )(ٌ .mainعرِّ ف التابع additionمتغٌّرا موضعٌّا)انظر فقرة المدى فً نهاٌة الدرس( جدٌدا rث ّم ٌسند إلٌه مجموع الوسٌطٌن .a, b ; a + b
= r
لكنّ a = 5, b = 3وبالنتٌجة فإنّ r = 8ث ّم ٌعٌد التابع القٌمة rباستخدام التعلٌمة ; return rأي أنّ قٌمة التابع هً العدد 9بعدها ٌخرج المترجم من التابع additionث ّم ٌعود إلى التعلٌمة ;)z = addition(5,3
وبما أنّ قٌمة التابع additionأصبحت 8فهذا ٌعنً أنّ z = 8أٌضا .كما فً الشكل: )int addition(int a,int b ;)
3
5 ,
(z = adition
ث ّم ٌكمل المترجم ما تبقى له من تعلٌمات التابع )(.main
6:
مثال: 5 5 2 6
is is is is
result result result result
1st 2nd 3rd 4th
The The The The
// function example >#include <iostream ;using namespace std )int sub(int a, int b { ;)return (a-b } )( int main { ;int x=5, y=3, z ;)z = sub(7,2 ;'cout<<"The 1st result is "<<z<<'\n ;'cout<<"The 2nd result is "<<sub(7,2)<<'\n ;'cout<<"The 3rd result is "<<sub(x,y)<<'\n ;)z = 4 + sub(x,y ;'cout << "The 4th result is " << z << '\n ;return 0 }
التوابع التً ال تعٌد قٌمة (استخدام الكلمة )void فً بعض األحٌان نحتاج إلى تابع ٌقوم بمجموعة من األشٌاء دون أن ٌعٌد قٌمة أو قد نرٌد منه أن ٌعٌد أكثر من قٌمة لكن وكما تعلّمنا فالتابع ٌجب أن ٌعٌد قٌمة وهذه القٌمة وحٌدة لذلك كان الحل باستخدام الطرق )الطرق methodsهو االسم الذي تستخدمه لغة javaلتع ّبر به عن التوابع التً ال تعٌد قٌما( .لكن ماهو الفرق؟ فً واقع األمر تشبه الطرٌقة التابع فً كل شًء ّإال أ ّنها ال تملك نوعا من البٌانات أل ّنها باألصل ال تعٌد قٌمة. ٌت ّم التصرٌح عن الطرٌقة بنفس األسلوب الذي صرّ حنا به عن التابع مع اختبلفٌن بسٌطٌن هما: -1لن نضع نوعا للبٌانات وبدال من ذلك سنستخدم الكلمة voidداللة على أنّ الطرٌقة التالٌة لن تعٌد شٌبؤ. -2بما أنّ الطرٌقة ال تعٌد أي قٌمة فبل داعً ألن نضع التعلٌمة returnفً نهاٌتها. وبذلك ٌكون شكل الطرٌقة كاآلتً: ) void method_name( void { ; statements . . .. }
مثال: !I'm a function
>#include <iostream ;using namespace std )void dummyfunction (void { ;"cout << "I'm a function!\n } )(int main { ; )(dummyfunction ;return 0 }
مالحظة :فً C++عندما نصرّ ح عن تابع أو طرٌقة دون وسطاء فلٌس من الضروري استخدام الكلمة voidبٌن القوسٌن )( لك ّننا نضعها لنشٌر إلى أنّ التابع ال ٌمتلك وسطاء. وممّا ٌجب علٌك أن تنتبه إلٌه عندما تستدعً أيّ تابع هو استخدام القوسٌن )( بعد اسم التابع ح ّتى ولو لم ٌمتلك وسطاء.
71
تمرٌر الوسطاء بالقٌمة و بالمرجع(العنوان)
فً األمثلة السابقة قمنا بتمرٌر الوسطاء بالقٌمة وهذا ٌعنً أ ّننا عندما نستدعً تابعا ذا وسطاء بالقٌمة فإ ّننا نمرّ ر قٌم المتغ ٌّرات إلى التوابع وال نمرّ ر المتغٌّرات نفسها .كمثال افترض أ ّننا استدعٌنا التابع additionفً المثال األول كاآلتً: ; int x = 5 , y = 3 , z ; )z = addition(x,y
ما فعلناه هنا هو أ ّننا استدعٌنا التابع additionومرّ رنا إلٌه قٌمتً المتغٌّرٌن xو yأي أ ّننا م ّررنا إلٌه الرقمٌن 5و 3ولم نم ّرر إلٌه المتغٌّرٌن xو .yكما فً الشكل. )int addition(int a,int b 3
;)
5
x ,
y
(z = adition
إنّ استدعاء الوسطاء بالقٌمة ٌمنع حدوث أي تغٌٌر على المتغٌّر الذي ت ّم تمرٌره إلى التابع خارج هذا التابع ولتوضٌح هذه المسؤلة نقدّم هذا المثال: // passing by values >#include<iostream ;using namespace std )int add(int a,int b { ;int result = a + b a--; b++; //changeing values of a and b ;return result } )(int main { ;int a=5,b=3,z ;cout<<"a and b before calling add function is: "<<a<<", "<<b<<endl ;)z = add(a,b ;cout<<"value of add function is: "<<z<<endl ;cout<<"a and b after calling add function is: "<<a<<", "<<b<<endl ;return 0 } a and b before calling add function is: 5, 3 value of add function is: 8 a and b after calling add function is: 5, 3
لعلّك الحظت أنّ قٌمتً المتغٌّرٌن aو bلم تتغٌّرا فً التابع)( mainح ّتى بعد استدعاء التابع additionالذي قام بالتعدٌل على الوسٌطٌن aو bالمعرّ فٌن فٌه والذٌن تغٌّرت قٌمتاهما كما هو واضح فً نتٌجة البرنامج السابق .لكن ماذا لو أردنا أن تتغٌر قٌم المتغ ٌّرات عند تمرٌرها إلى تابع ما؟ عندها لن ٌكون تمرٌرها بالقٌمة مجدٌا وٌتح ّتم علٌنا عندب ٍذ أن نم ّررها بالمرجع )العنوان(. عندما نم ّرر متغٌّرا ما بالمرجع إلى أحد التوابع فإ ّننا ال نمرّر قٌمته وحسب بل نمرّر المتغٌّر نفسه أي أنّ أيّ تغٌٌر على المتغٌّر الوسٌط فً التابع س ٌَحْ ُد ُ ث على المتغٌّر ح ّتى خارج هذا التابع. وٌت ّم االستدعاء بالمرجع من خبلل استخدام المعامل & بعد نوع الوسٌط الذي نرغب بتمرٌره بالمرجع فً جسم التابع كما فً الشكل: )void duplicate (int& a, int& b, int& c
z ) z
y ,
x y
,
x
( duplicate
72
:المثال التالً ٌوضح ذلك // passing parameters by reference #include <iostream> using namespace std; void duplicate (int& a, int& b, int& c) { a*=2; b*=2; c*=2; } int main () { int x=1, y=3, z=7; cout<<"x,y,z before calling duplicate"; cout <<"\nx="<<x<<", y=" << y <<", z=" <<z<<endl; duplicate (x, y, z); cout<<"x,y,z after calling duplicate\n"; cout <<"x="<<x<<", y=" << y <<", z=" <<z<<endl; return 0; }
x,y,z before calling duplicate x=1, y=3, z=7 x,y,z after calling duplicate x=2, y=6, z=14
أ ُ ْت ِب َع نوعُه بالرمز & الذي ٌعنً أنّ هذا الوسٌطduplicate ٌجب أن تنتبه إلى أنّ ك ّل وسٌط فً التابع .سٌمرّ ر بالمرجع و لٌس بالقٌمة كما فً الحالة األولى ولكنّ تمرٌر الوسطاء,كما قلنا فً بداٌة هذا الدرس إنّ التوابع تعٌد قٌمة وحٌدة بٌنما ال تعٌد الطرق أ ٌّة قٌمة .بالمرجع ٌع ّد أداة قوٌة تستطٌع من خبللها أن تجعل التابع )الطرٌقة( ٌعٌد أكثر من قٌمة :والمثال التالً ٌوضّح هذا الذي ٌقبل ثبلثة وسطاء حٌث ٌؤخذ الوسٌط األوّ ل وٌعٌد الرقم الذي ٌسبقه كقٌمة له منprevnext لدٌنا التابع .خبلل الوسٌط الثانً كما ٌعٌد الرقم الذي ٌلً الوسٌط األول كقٌمة له من خبلل الوسٌط الثالث // more than one returning value #include <iostream> using namespace std; void prevnext (int x,int& prev, int& next) { prev = x-1; next = x+1; } int main () { int x=100, y, z; prevnext (x, y, z); cout<<"Previous=" << y << ", Next="<< z << endl; return 0; }
Previous=99, Next=101
: بالشكلprevnext ٌمكنك كتابة التابع: مالحظة int prevnext (int x,int& prev, int& next) { prev = x-1; next = x+1; return 0;}
73
المدى Scope ك ّل المتغٌّرات التً سنستخدمها فً برامجنا ٌجب أن ٌت ّم التصرٌح عنها أوالٌ .مكن التصرٌح عن المتغٌّرات فً ُعرفُ بمجال الرإٌا أيّ مكان من صفحة الشٌفرة .لكنْ هناك شٌا ٌجب أن تعلمه عزٌزي القارئ ,وهو ما ٌ َ للمتغٌّر )المدى( .تابع الشكل التالً أوال:
Global Variables
Local Variables متغيراث موضعيت
Instructions
>#include<iostream ;using namespace std ; int Integer ; char aCharacter ; ]char string[20
)(int main { ; unsigned short Age ; float ANumber , AnotherOne ;" cout << "Enter Your age: ;cin >> Age … ; return 0 }
المتغ ٌّرات الشاملة Global variablesو المتغ ٌّرات الموضع ٌّة :Local variables المتغ ٌّرت الشاملة هً المتغٌّرات التً ٌُصرّ ح عنها أعلى البرنامج خارج كل التوابع كما هو واضح فً الشكل السابق فالمتغٌّرات ] Integer , aCharacter , string [20كلّها متغٌّرات شاملة. ٌمكن الوصول إلى هذه المتغٌّرات من أي مكان داخل الشٌفرة ,و من أي تابع أو البرنامج.
طرٌقة(إجراء)
معرّ فة فً
صرح عنها داخل القوسٌن وهذا ماال تستطٌع المتغٌّرات الموضعٌّة أن تفعله ,والمتغ ٌّرات الموضع ٌّة هً التً ٌ ّ }{ لتابع أو إجراء أو بنٌة برمجٌة ما فً البرنامج. فً الشكل السابق المتغٌّرات Age , ANumber , AnotherOneصُرِّ ح عنها فً جسم التابع )( mainأي أ ّننا قادرون على الوصول إلٌها من داخل التابع )( mainفقط .وهذا ٌعنً أ ّنه لن ٌكون بمقدورنا أن نصل إلى أحد هذه المتغٌّرات من أي تابع آخر مع ّرف فً البرنامج. فً C++المدى للمتغٌّر الموضعًّ محدّد فقط فً البنٌة البرمجٌة التً صُرِّ َح عنه فٌها ف فٌه ,ولو أ ّنه مجموعة التعلٌمات المحصورة بٌن القوسٌن }{) أي لو أ ّنه عُرِّ ف ضمن التابع فإنّ مداه هو التابع الذي عُرِّ َ ف ضمن إحدى البنى التكرارٌة فإنّ مداه هو تلك البنٌة التكرارٌّة وحسب. عُرِّ َ
(البنٌة البرمجٌة المقصودة هً
مالحظة :المتغٌرات الشاملة تتم تبدأتها مع بداٌة البرنامج قبل التابع mainبشكل تلقابً إلى القٌم الصفرٌة لكل نوع فمثبل المتغٌر ٌ Integerؤخذ القٌمة 1تلقابٌا )جرّ ب أن تطبع قٌم المتغٌرات الشاملة من المثال السابق ستجد أن المتغٌرات الحرفٌة تطبع فراغات )أو ال تطبع شٌبا(( أمّا المتغٌرات الموضعٌة فٌت ّم تبدأتها عندما ٌصل المترجم إلى مكان التصرٌح عنها وهً تأخذ قٌما ا عشوائٌة بشكل تلقائً ما لم تقم بتبدئتها بنفسك.
74
المتغٌرات الثابتة static هذا النوع من المتغٌرات تت ّم تبدأته مرة واحدة فقط وٌمكن أن تتغٌر قٌمته )ٌوجد منه نسخة واحدة فقط( مثال: 0 0 0 0
== == == ==
x x x x
, , , ,
0 1 2 3
== == == ==
// Example static variables >#include <iostream.h )void f(int a { )while(a-- != 0 { static int n = 0 ;// initialized once ; int x = 0 // initialized n times ;"cout<<"n == "<<n++<<", x == "<<x++<<"\n } } )( int main { ;)f(4 ;return 0 }
n n n n
تعٌٌن القٌمة االفتراضٌة للوسطاء
عندما نصرّ ح عن متغٌّر فإ ّننا نستطٌع أن نعطٌه قٌمة ابتدابٌة ث ّم قد نرغب بتغٌٌر قٌمته فٌما بعد أثناء البرنامج لكن هل نستطٌع أن نعطً قٌمة ابتدائٌة لوسٌط معرف داخل تابع ما؟ ال تتعجّ ب إن ُ قلت لك" :نعم" .فً الحقٌقة ٌع ّد هذا ممكنا من أجل ك ّل وسٌط ترٌد أن تعطٌه قٌمة ابتدابٌة لتكون قٌم َته االفتراضٌة فً حال لم تقم بوضع أيّ قٌمة فً مكان هذا الوسٌط عند استدعاء التابع ,ولكن لو قمت بوضع قٌمة أخرى أثناء استدعاء التابع فسٌعتبر المترجم أنّ قٌمة الوسٌط هً القٌمة التً أدخلتها عند استدعاء التابع وسٌتجاهل القٌمة االفتراضٌة تلك. مثال: 6 5
// default values in functions >#include <iostream ;using namespace std )int divide (int a, int b=2 { ;int r ;r=a/b ;)return (r } )( int main { ;)cout << divide (12 ;cout << endl ;cout << divide (20,4)<<endl ;return 0 }
كما ترى فإنّ ناتج التعلٌمة ) divide(12هو العدد 4أل ّننا لم نضع قٌمة للوسٌط الثانً bالذي ٌؤخذ القٌمة 3كقٌمة افتراضٌة له لذلك فإنّ divide(12) = 12 / 2 = 6 أمّا فً الحالة الثانٌة فقد استدعٌنا التابع بالشكل ) divide(20,4أي أ ّننا طلبنا منه أن ٌغٌّر القٌمة االفتراضٌة للوسٌط bلتصبح العدد 6وعندها ٌكون الناتج .divide(20,4) = 20 / 4 = 5
75
إعادة تحمٌل التوابع functions overloading
لو كان لدٌنا تابعان ٌقومان بنفس التعلٌمات تماما وٌمتلكان نفس االسم أٌضا لك ّنهما ٌختلفان عن بعضٌهما ُعرفُ بإعادة التحمٌل بالوسطاء وهذا االختبلف قد ٌكون فً األنواع أو فً عدد الوسطاء المطلوبة ,فهذا ما ٌ َ التوابع. وإلٌك المثال التالً: 2 2.5
//overloaded function >#include<iostream ;using namespace std )int divide (int a, int b } ;){ return (a/b )float divide (float a, float b } ;){ return (a/b )( int main { ;int x=5,y=2 ;float n=5.0,m=2.0 ;)cout << divide (x,y ;"cout << "\n ;)cout << divide (n,m ;"cout << "\n ;return 0 }
ٌستطٌع المترجم أن ٌحدّد أيّ التابعٌن سٌستخدم من خبلل نوع االوسطاء التً س ُتمرِّ رُها فإذا كانت أعدادا صحٌحة سٌستدعً التابع المعرّ ف أوّ ال والذي ٌقبل وسطاء من النوع intوإذا كانت الوسطاء من النوع floatعندها سٌستخدم التابع الثانً. ٌفٌدنا هذا األسلوب فً التقلٌل من أسماء التوابع التً سنستخدمها فً برنامجنا ,فطالما أنّ هذه التوابع تقوم بنفس العمل ,فلِم ال تؤخذ نفس االسم.
التعرٌف المبدئً للتوابع functions prototype
ح ّتى اآلن ك ّل التوابع التً قمنا بكتابها صرّ حنا عنها فوق التابع mainلكً نستطٌع استدعاءها فً التابع )( , mainلكن ماذا لو أردنا أن نكتب تابعا ا ما تحت التابع )(main؟ ٌمكننا فعل ذلك ولكن باستخدام الطرٌقة التالٌة: نصرّ ح عن التابع فً أعلى البرنامج قبل التابع )( mainبالشكل التالً: ;)data_type function_name (argument_type1, argument_type2... مع مراعاة األمور التالٌة: ٌ جب ّأال تكتب أٌّة تعلٌمة من جسم التابع فً هذا التصرٌح. ٌ جب أن تضع فاصلة منقوطة فً نهاٌة هذا التصرٌح. ٌُ كتفى بوضع أنواع البٌانات للوسطاء دون أسمابها ,وٌع ّد كتابة األسماء أمرا اختٌارٌا وهو األفضل. ث ّم تحت التابع )( mainنقوم بكتابة جسم التابع.
76
:مثال // prototyping #include <iostream> using namespace std; void odd (int a); void even (int a); int main () { int i; do { cout << "Type a number(0 to exit): "; cin >> i; odd (i); } while (i!=0); return 0; } void odd (int a) { if ((a%2)!=0) cout<<"Number is odd.\n"; else even (a); } void even (int a) { if((a%2)==0) cout <<"Number is even.\n"; else odd (a); }
77
Type a Number Type a Number Type a Number Type a Number
number (0 is odd. number (0 is even. number (0 is even. number (0 is even.
to exit): 9 to exit): 6 to exit): 1030 to exit): 0
الفصل الثامن:
التعاود ٌّة :هً خاصٌّة ٌستطٌع التابع من خبللها أن ٌستدعً نفسه. وتستخدم هذه الطرٌقة لحل المشاكل التً ٌمكن ردّها إلى مشكلة واحدة مكرّ رة عدّة مرّ ات ,و ٌعتبر هذا األسلوب مفٌدا من أجل بعض طرق الترتٌب أو لحساب عاملً عدد ما ! nوالذي ٌعطى بالعبلقة التالٌة: وٌُصطلح على أنّ : لو تؤملنا العبلقة ج ٌّدا سنجد أ ّنها تكتب أٌضا بالشكل التالً: وكمثال لنؤخذ الرقم 6ونحسب العاملً له: = 24
)1
2.
(3.
4! = 4.
أو 2! = 4. 3. 2. 1! = 24 واآلن سنكتب برنامجا ٌستخدم تابعا تعاود ٌّا لح ّل هذه المشكلة: Type a number: 4 4! = 732
3.
3! = 4.
4.
= !4
// factorial calculator >#include <iostream ;using namespace std )long fact(long n { )if (n > 1 !)return (n * fact(n-1)); // n.(n-1 else ;)return (1 } )( int main { ;long m ;" cout << "Type a number: ;cin >> m ;cout<<"\n"<<m<<"! = "<<fact(m)<<endl ;return 0 }
لعلّك الحظت أنّ التابع factقام باستدعاء نفسه من خبلل التعلٌمة ))return (n * fact(n-1 وهذا ما ٌُعرف بالتعاودٌّة .والمقصود بهذا أنّ التابع لن ٌكمل تنفٌذ التعلٌمات الموجودة بعد هذه التعلٌمة وإ ّنما لٌستدعً نفسه من جدٌد ,وذلك ألنّ قٌمة االستدعاء األوّ ل مرتبطة باستدعاء جدٌد للتابع نفسه وقٌمة هذا سٌعود َ االستدعاء الجدٌد مرتبطة باستدعاء آخر سٌتحقق بمجرّ د وصول المترجم إلى نفس السطر من االستدعاء الذي ٌنفذه حالٌا وتستمر هذه ْ الحلقة من االستدعاءات المترابطة مع بعضها وٌستمر المترجم بحجز أماكن جدٌدة من الذاكرة لكل المتغٌّرات الموجودة فً التابع المُس َت ْدعى ولكن إلى متى؟
78
ٌعتبر شرط التوقف الذي ٌجب أن تضعه فً التابع أه ّم ما ٌجب علٌك فعله أل ّنك لو لم تفعل فإنّ البرنامج سٌدخل فً حلقة تعاودٌّة النهابٌّة نتٌجتها تو ّقف البرنامج بخطؤ من النوع .stack overflow شرط التوقف هو شرط ٌإدّي تح ّققه إلى تنفٌذ تعلٌمة ال تحتوي على استدعاء جدٌد للتابع ومن المه ّم أن ٌكون هذا الشرط قاببل للتح ّقق لكً ٌتوقف التابع عن استدعاء نفسه ّ وإال فلٌس لهذا الشرط أٌّة قٌمة .فً مثالنا السابق الجزء الثانً من تعلٌمة الشرط هو شرط التوقف .اآلن لنعد إلى برنامجنا السابق ولندخل عالم التعاودٌّة الملًء بالمغامرات. التابع factمن أجل القٌمة 5
التابع factمن أجل القٌمة 3 fact(3) : 3 > 1 ? yes )fact(3) = 3 * fact(2 fact(2) : 2 > 1 ? yes )fact(2) = 2 * fact(1 fact(1) : 1 > 1 ? no return 1 fact(2) = 2 * 1 = 2 return 2 fact(3) = 3 * 2 = 6 return 6
كما تبلحظ ُتحسب قٌم ُة االستدعاء األخٌر أوّ ال ث ّم الذي قبله ث ّم الذي قبله ح ّتى ٌصل إلى االستدعاء األوّ ل مجسدا بذلك فكرة المكدّس stackوهً تقول" :آخ ُر الداخلٌن هو أوّ ل الخارجٌن )."(Last in first out هل ٌجب علٌنا أن نستخدم هذا األسلوب دائماا؟ فً الحقٌقة إنّ استخدام هذا األسلوب مرب ٌ ك كثٌرا وٌكمن البدٌل فً استخدام البنى التكرارٌّة ,فالقاعدة تقول" :البرنامج الذي ٌمكن كتابته بشكل تعاوديّ ٌمكن كتابته بشكل تكراري وهذا أفضل وأسرع" .لنكتب المثال السابق بشكل تكراري: Type a number: 9 9! = 362880
// factorial calculator >#include <iostream ;using namespace std )long fact(int a { ;long f = 1 )for(int i = a ; i>0 ; i-- ;f *= i ; //or f = f * i ; return f } )( int main { ;long l ;" cout << "Type a number: ;cin >> l ;)cout << "\n" << l << "! = " << fact(l ;cout<<endl ;return 0 }
79
:اكتب التابع factباستخدام الحلقتٌن التكرارٌتٌن الباقٌتٌن. مثال :اٌجشٔبِظ اٌزبٌ٠ ٟم َٛثؾغبة ِغّٛع اٌغٍغٍخ اٌّىٔٛخ ِٓ األػذاد اٌطج١ؼ١خ ثبٌشىً:
Enter n: 4 sum(4) = 10
>#include<iostream ;using namespace std )int sum(int n { )if ( n > 1 ;)return n+sum(n-1 else ;return 1 } )(int main { ; int n ;" cout<< "Enter n: ;cin>> n ;cout << "\nsum(" << n << ")= " << sum(n) << endl } sum(3) : 3 > 1 ? yes )sum(3) = 3 + sum(2 sum(2) : 2 > 1 ? yes )sum(2) = 2 + sum(1 sum(1) : 1 > 1 ? no return 1 sum(2) = 2 + 1 = 3 return 3 sum(3) = 3 + 3 = 6 return 6
سلسلة فٌبوناكسً :Fibonacci numbers عٕىزت ربثؼب ً رؼبٚدّ٠ب ً إل٠غبد األسلبَ اٌزبٌ١خ:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34,.. .
ؽ١ش ّ أْ اٌشلُ األوجش ِٓ ٕ٠ 1زظ ِٓ ِغّٛع اٌشلّ ٓ١اٌز٠ ٓ٠غجمبٔٗ ٚفك اٌؼاللبد اٌزبٌ١خ: fib(0) = 0, fib(1) = 1 fib(n) = fib(n-1) + fib(n-2) :n>1. ٘ٚزٖ اٌغٍغٍخ رؼط ٟإٌغجخ اٌز٘ج١خ اٌز ٟرٛعذ ثىضشح ف ٟاٌطج١ؼخ ٟ٘ٚرٕزظ ِٓ اٌمغّخ ٟ٘ٚاٌّغزخذِخ ف ٟئٔشبء إٌٛافز ٚاٌغشف ٚاٌّجبٔ ٟؽ١ش رّضً ٔغجخ اٌطٛي ئٌ ٝاٌؼشع.
7:
#include<iostream> using namespace std; int fib(int n) { if ( n == 0 || n == 1 ) return n; else return (fib(n-1)+fib(n-2)); } int main() { int n ; cout<< "Enter n: "; cin>> n; cout<< "\nfib(" << n << ") = " << fib(n) << endl; }
1- fib(4): 4 ?= 0 no, or 4 ?= 1 no fib(4) = fib(3) + fib(2) 2- fib(3): 3 ?= 0 no, or 3 ?= 1 no fib(3) = fib(2) + fib(1) 3- fib(2): 2 ?= 0 no, or 2 ?= 1 no fib(2) = fib(1) + fib(0) 4- fib(1): 1 ?= 0 no, or 1 ?= 1 yes fib(1) = 1 return fib(1) 5- fib(0): 0 ?= 0 yes, or 0 ?= 1 no fib(0) = 0 return fib(0) fib(2) = 1 + 0 return fib(2) fib(3) = 1 + fib(1) 6- fib(1): 1 ?= 0 no, or 1 ?= 1 yes fib(1) = 1 return fib(1) fib(3) = 1 + 1 = 2 return fib(3) fib(4) = 2 + fib(2)
81
Enter n: 4 fib(4) = 3
7- fib(2): 2 ?= 0 no, or 2 ?= 1 no fib(2) = fib(1) + fib(0) 8- fib(1): 1 ?= 0 no, or 1 ?= 1 yes fib(1) = 1 return fib(1) 9- fib(0): 0 ?= 0 yes, or 0 ?= 1 no fib(0) = 0 return fib(0) fib(2) = 1 + 0 return fib(2) fib(4) = 2 + 1 = 3
82
.1ماهو ناتج تنفٌذ التوابع التالٌة: C
B
A
>#include<iostream ;using namespace std )int sum(int a { )if(a>1 ;)return a+sum(a-1 )else if(a==1 ;return a ;else return 0 } )(int main { ;cout<<sum(5)<<endl ;return 0 }
>#include<iostream ;using namespace std )int sum(int a { )if(a>1 ;)return a+sum(a-- )else if(a==1 ;return a ;else return 0 } )(int main { ;cout<<sum(5)<<endl ;return 0 }
>#include<iostream ;using namespace std )int sum(int a { )if(a>1 ;)return a+sum(--a )else if(a==1 ;return a ;else return 0 } )(int main { ;cout<<sum(5)<<endl ;return 0 }
C ٌطبع القٌمة 15
B ٌحدث خطؤ من النوع stack overflow
A ٌطبع القٌمة 11
=sum 15 + 12 + 4 + 2 + 1
C =a 5 6 2 3 1
االستدعاء 1 3 2 6 5
=sum not calculated not calculated not calculated not calculated not calculated
B = aاالستدعاء 1 5 3 5 2 5 6 5 ... ...
=sum 11 + 7 + 6 + 3 + 1
A = aاالستدعاء 1 5 3 6 2 2 6 3 5 1
الحالة Aنجد التعلٌمة ;) return a+sum(--aفً هذه التعلٌمة المعامل ٌ --aؤخذ أولوٌة التنفٌذ ح ّتى ولو كان فً ٌمٌن التعلٌمة لذلك فإنّ قٌمة aستتغ ٌّر أوّ ال ث ّم سٌت ّم االستدعاء التالً ,وسٌكون ناتج التابع كما هو ضح فً الجدول .A مو ّ الحالة Bنجد التعلٌمة ;) return a+sum(a--فً هذه التعلٌمة المعامل ٌ a--ؤخذ أولوٌة التنفٌذ ح ّتى ولو كان فً ٌمٌن التعلٌمة لكنّ قٌمة aلن تتغ ٌّر ح ّتى ٌنتقل المترجم إلى التعلٌمة التالٌة ّإال أنّ االستدعاء التالً سٌت ّم وستكون قٌمة aعندها نفسها فً االستدعاء السابق أي أنّ شرط تو ّقف التعاودٌّة لن ٌتحقّق أبدا ممّا ٌسبب الخطؤ المذكور فً الجدول .B الحالة Cنجد التعلٌمة ;) return a+sum(a-1فً هذه التعلٌمة a-1تنقص قٌمة aبمقدار 1فً االستدعاء التالً ,وسٌكون ناتج التابع كما هو موضح فً الجدول .C )راجع فصل المعامبلت .فقرة (6معامبلت الزٌادة و النقصان(
83
ٌُ .3قا ُل عن عد ٍد ما إ ّنه تا ٌّم إذا كان ٌساوي مجموع قواسِ مه كلِّها باإلضافة إلى العدد 1ما عدا العدد نفسه. مثال: 6 = 1 + 2 + 3 اكتب برنامجا فٌه إجرا ٌء ٌطبع العبارة Is perfectإذا كان العدد المدخل تامّا وٌطبع sn't perfectإذا لم ٌكن تامّا.
.0
الخوارزمٌة (للتابع فقط)
-1من أجل i = 1حتى i = a-1 إذا كان ٌ iقسم aأضفه إلى مجموع القواسم
-3إذا كان المجموع ٌساوي aاطبع perfect و إال فاطبع not perfect .2الشٌفرة >#include<iostream ;using namespace std ;)void isperfect(int a )(int main { ;int n ;" cout<<"Enter number: ;cin>>n ;)isperfect(n ;return 0 } )void isperfect(int a { ;int sum = 0 )for(int i = 1; i< a;i++ )if(a%i == 0 ;sum+= i ;"(sum == a)? cout<<a <<" perfect\n":cout<< a<<" not perfect\n }
.2أبراج هانوي ()Towers of Hanoi رؼزشع ٘زٖ اٌّشىٍخ ِؼظُ ِزؼٍّ ٟاٌجشِغخ ٟ٘ٚرؼٛد ئٌِٕ ٝبؽك ف ٟششق آع١ب ؽ١ش وبْ ف ٟاٌّؼجذ صالصخ أػّذح األٚي ف 46 ٗ١لشطب ً ِشرجخ رظبػذ٠ب ً ِٓ األػٍ ٝئٌ ٝاألعفً ثؾ١ش ٠ى ْٛأوجش٘ب ف ٟأعفً اٌؼّٛد ٚرمٛي األعطٛسح" :ئّٔٗ ػٕذِب ٕ٠ز ٟٙاٌش٘جبْ ِٓ ٔمً وً ٘زٖ األلشاص ئٌ ٝاٌؼّٛد اٌضبٌش عٕ١ز ٟٙاٌؼبٌُ"ٌٚ ,ىٕ٠ ٟمً اٌش٘جبْ ٘زٖ األلشاص ٠غت أْ ٠شاػٛا اٌمبػذح اٌزبٌ١خ: ٌ -2جب نقل قرص واحد فقط فً ك ّل مرّ ة. ٌ -3جب استخدام أحد األعمدة كوسٌط مإقت. -4ال ٌجوز أن تضع قرصا كبٌرا فوق قرص أصغر منه أبدا. مهم ّتنا اآلن أن نساعد هإالء الرهبان على إٌجاد الطرٌقة األفضل لح ّل هذه المشكلة. حٌث سنكتب تابعا تعاود ٌّا ٌقبل الوسطاء التالٌة: n 1 عدد األقراص from العمود الموجودة علٌه األقراص to العمود الذي سننقل األقراص إلٌه temp العمود الوسٌط المإقت ث ّم ٌطبع الخطوات البلزمة لنقل األقراص اعتمادا على القاعدة السابقة. 84
لدٌنا ثبلثة أقراص نرٌد نقلها من العمود األول إلى العمود الثالث باالعتماد على العمود الثانً كوسٌط:مثال .مإقت Move Disk (1) from Move Disk (2) from Move Disk (1) from Move Disk (3) from Move Disk (1) from Move Disk (2) from Move Disk (1) from
1to3 1to2 3to2 1to3 2to1 2to3 1to3
الخوارزمٌة.0 n = 1 إذا كان-1 .انقل القرص من العمود األول إلى العمود الثالث من دون اللجوء إلى العمود الوسٌط المإقت : و إال افعل الخطوات التالٌة-3 . من العمود األول إلى العمود الثانً باستخدام العمود الثالث كوسٌط مإقتn-1 انقل القرص رقم-a . انقل القرص األخٌر من العمود األول إلى العمود الثالث-b . من العمود الثانً إلى العمود الثالث باستخدام العمود األول كوسٌط مإقتn-1 انقل القرص رقم-c الشٌفرة.2 #include<iostream> using namespace std; int han(int n,int a,int b,int t); int main() { int n,from=1,to=3,temp=2; cout<<"Enter n, from, to, temp\ne.g: 3\n1\n3\n2\n\n\n"; cin>>n>>from>>to>>temp; han(n,from,to,temp); return 0; } int han(int n,int from,int to,int temp) { if(n ==1) cout<<"Move Disk ("<<n<<") from "<< from<<" to "<< to <<"\n"; else { han(n-1,from,temp,to); cout<<"Move Disk ("<<n<<") from "<< from<<" to "<< to <<"\n"; han(n-1,temp,to,from); } return 0; }
85
โ ซโ ช .1โ ฌุฃู ุฌุฏ ุงุฃู ุฎุทุงุก ู ู ุงู ุชู ุงุจุน ุงู ุชุงู ู ุฉโ ช:โ ฌโ ฌ โ ซ)โ ช1. int Sum(int a , int bโ ฌโ ฌ โ ซ{โ ฌ โ ซ;โ ชint sum = a + bโ ฌโ ฌ โ ซ}โ ฌ โ ซ)โ ช2. int divide(int a , int bโ ฌโ ฌ โ ซ{โ ฌ โ ซ;โ ชreturn (float)a/bโ ฌโ ฌ โ ซ}โ ฌ โ ซ)โ ช3. void subtract(int a , int bโ ฌโ ฌ โ ซ{โ ฌ โ ซ;โ ชreturn a-bโ ฌโ ฌ โ ซ}โ ฌ
โ ซโ ช .2โ ฌู ุง ู ู ู ุงุชุฌ ุงู ุจุฑู ุงู ุฌ ุงู ุชุงู ู โ ช:โ ฌโ ฌ โ ซ>โ ช#include<iostreamโ ฌโ ฌ โ ซ;โ ชusing namespace stdโ ฌโ ฌ โ ซ;โ ชint x = 0โ ฌโ ฌ โ ซ;โ ชfloat bโ ฌโ ฌ โ ซ)โ ชfloat d(float a , float& bโ ฌโ ฌ โ ซ{โ ฌ โ ซ;โ ชa--โ ฌโ ฌ โ ซ;โ ชb++โ ฌโ ฌ โ ซ;โ ชx = a/bโ ฌโ ฌ โ ซ;โ ชreturn (x+1)/2.0โ ฌโ ฌ โ ซ}โ ฌ โ ซ)(โ ชint mainโ ฌโ ฌ โ ซ{โ ฌ โ ซ;โ ชfloat aโ ฌโ ฌ โ ซ;"โ ชcout<<"x\tb\ta\nโ ฌโ ฌ โ ซ;โ ชcout<<x<<"\t"<<b<<"\t"<<a<<endlโ ฌโ ฌ โ ซ;โ ชa = b = ++xโ ฌโ ฌ โ ซ;โ ชcout<<d(a , b)<<endlโ ฌโ ฌ โ ซ;โ ชcout<<x<<"\t"<<b<<"\t"<<a<<endlโ ฌโ ฌ โ ซ;โ ชreturn 0โ ฌโ ฌ โ ซ}โ ฌ โ ซู ุงุฐุง ุณู ู ู ู ู ุงุชุฌ ุงู ุจุฑู ุงู ุฌ ุงู ุณุงุจู ู ู ุงุณุชุจุฏู ู ุง ุงู ุชุนู ู ู ุฉ ;โ ช return (x+1)/2.0โ ฌุจุงู ุชุนู ู ู ุฉโ ฌ
โ ซ;โ ช return ++x/2.0โ ฌุ โ ช.โ ฌโ ฌ โ ซโ ช .3โ ฌุงู ุชุจ ุจุฑู ุงู ุฌุง ู ู ู ู ุจุงู ุนู ู ู ู ุงุช ุงู ุฑู ุงุถู ู ุฉ ุงุฃู ุฑุจุน ู ุฐู ู ุจุงุณุชุฎุฏุงู ุงู ุชู ุงุจุนโ ช.โ ฌโ ฌ โ ซุซ ู ู ุงู ุชุจู ุจุงุณุชุฎุฏุงู ุชุงุจุน ุชู ุฑุงุฑู โ ช.โ ฌโ ฌ โ ซโ ช .4โ ฌุจุงุณุชุฎุฏุงู ุชุงุจุน ุชุนุงู ุฏู ู ุงู ุชุจ ุจุฑู ุงู ุฌุง ู ุญุณุจ ุงู ุนุฏุฏโ ฌ โ ซ)ู ุน ู ุงู ุญุธุฉ ุฃู ู โ ช:โ ฌโ ฌ
โ ซู ู โ ฌ
โ ซู โ ฌ
โ ซ(โ ฌ
โ ซู โ ฌ
โ ซโ ช .5โ ฌุงู ุชุจ ุจุฑู ุงู ุฌุง ู ู ู ุชุงุจุน ู ู ู ู ุจุฅู ุฌุงุฏ ู ุฌู ู ุน ุงู ุณู ุณู ุฉ ุงู ุชุงู ู ุฉโ ช:โ ฌโ ฌ โ ซโ โ ฌ
โ ซ๐ โ ฌ
โ ซุงุนุชู ุฏ ุนู ู ุงู ุชู ุฑู ู ุงู ุณุงุจู ู ุญุณุงุจโ ช.โ ฌโ ฌ
โ ซโ ช .6โ ฌุงู ุชุจ ุจุฑู ุงู ุฌุง ุฅู ู ุฌุงุฏ ุงู ู ุงุณู ุงู ู ุดุชุฑู ุงุฃู ู ุจุฑ ู ุนุฏุฏู ู ุจุงุณุชุฎุฏุงู ุชุงุจุน ุชู ุฑุงุฑู ู ุขุฎุฑ ุชุนุงู ุฏู โ ฌ โ ซุนู ู ุง ุฃู ู โ ช.GCD(x , y) = GCD(x , x % y) :โ ฌโ ฌ โ ซโ ช86โ ฌโ ฌ
โ ซ) (โ ฌ
โ ซโ ช .7โ ฌุงู ุชุจ ุจุฑู ุงู ุฌุง ู ู ู ุชุงุจุน ู ุญุณุงุจ !โ ช nโ ฌู ุขุฎุฑ ู ุญุณุงุจโ ฌ โ ซู ุขุฎุฑ ู ุญุณุงุจโ ฌ
โ ซ) (โ ฌ
โ ซโ ช .8โ ฌุงู ุชุจ ุชุงุจุนุง )ุฅุฌุฑุงุก( ุงุณู ู โ ช multipleโ ฌุจุญู ุซ ู ุคุฎุฐ ุนุฏุฏู ู ุตุญู ุญู ู ู ู ุณู ุทู ู ุซ ู ู ู ุนู ุฏ )ู ุทุจุน( โ ช trueโ ฌุฅุฐุงโ ฌ โ ซู ุงู ุงู ุนุฏุฏ ุงู ุซุงู ู ู ู ู ุถุงุนู ุงุช ุงู ุนุฏุฏ ุงุฃู ู ู ู ุฅุงู ู ู ุนู ุฏ )ู ุทุจุน( โ ช.falseโ ฌโ ฌ โ ซโ ช .9โ ฌุงู ุชุจ ุจุฑู ุงู ุฌุง ู ู ู ู ุชุงุจุน ู ู ู ู ุจู ุญุต ุฑู ู ุตุญู ุญ ู ู ุฑู ุฑ ุฅู ู ู ู ู ุนู ุฏ ู ู ู ุฉ ู ู ุทู ู ู ุฉ โ ช trueโ ฌุฅุฐุง ู ุงู ุฃู ู ู ู ุง ู โ ฌ โ ซโ ช falseโ ฌุฅุฐุง ู ู ู ู ู โ ช ,โ ฌุซ ู ู ุงุณุชุฎุฏู ุฅุฌุฑุงุก ู ู ู ู ุจุทุจุงุนุฉ ู ู ุงุฃู ุฑู ุงู ุงุฃู ู ู ู ู ุฉ ุจู ู โ ช 1โ ฌู ุงู ุฑู ู ุงู ู ุฏุฎู โ ชู ).โ ฌู ู ู ู ุงุณุชุฎุฏุงู โ ฌ โ ซุงู ุชุงุจุน ุงู ุณุงุจู ุฏุงุฎู ู ุฐุง ุงุฅู ุฌุฑุงุก(โ ช.โ ฌโ ฌ โ ซู ุจู ุญุธุฉ โ ช :โ ฌุงู ุฑู ู ุงุฃู ู ู ู ู ู ู ุงู ุฑู ู ุงู ุฐู ู ู ุจู ุงู ู ุณู ุฉ ุนู ู ู ู ุณู ู ุนู ู โ ช 1โ ฌู ู ุทโ ช .โ ฌู ุงู ุฑู ู โ ช 1โ ฌู ู ุณ ุฃู ู ู ู ุงโ ช.โ ฌโ ฌ
โ ซโ ช .10โ ฌุงู ุชุจ ุจุฑู ุงู ุฌุง ู ู ู ุชุงุจุน ู ุญุณุงุจ ุงู ู ู ู ุฉ ุงู ู ุทู ู ุฉ ู ุนุฏุฏ ู ุงโ ช .โ ฌุนู ู ุง ุฃ ู ู ู ุง ุชุญ ู ู ู ุงู ุดู ู ุงู ุชุงู ู โ ช:โ ฌโ ฌ โ ซ| |โ ฌ
โ ซ{โ ฌ โ ซโ ช .11โ ฌุงู ุชุจ ุจุฑู ุงู ุฌุง ู ู ู ุซุจู ุซุฉ ุชู ุงุจุน ู ู ุง ู ู ู โ ช:โ ฌโ ฌ โ ซโ ชู ๏ ทโ ฌุญุณุจ ู ุณุงุญุฉ ุฏุงุจุฑุฉ ุจุนุฏ ุฅุฏุฎุงู ู ุตู ู ุทุฑู ุง โ ชrโ ฌโ ฌ โ ซโ ชู ๏ ทโ ฌุญุณุจ ู ุณุงุญุฉ ู ุณุชุทู ู ุจุนุฏ ุฅุฏุฎุงู ุทู ู ู ุถู ุนู ู โ ชa, bโ ฌโ ฌ โ ซโ ช๏ ทโ ฌโ ฌ
โ ซ๐ โ ฌ
โ ซู ุญุณุจ ู ุณุงุญุฉ ู ุซู ุซ ุจุนุฏ ุฅุฏุฎุงู ุทู ู ู ุงุนุฏุชู โ ช bโ ฌู ุงุฑุชู ุงุนู โ ชhโ ฌโ ฌ
โ ซุญู ุซ ู ุนุฑุถ ุงู ุจุฑู ุงู ุฌ ู ุงุจู ุฉ ู ู ู ุง ุงู ุฎู ุงุฑุงุช ุงู ู ู ู ู ุฉ ู ู ุฎุชุงุฑ ุงู ู ุณุชุฎุฏู ุฃุญุฏู ุง ู ู ุง ู ู ุงู ุดู ู ุงู ุชุงู ู โ ช:โ ฌโ ฌ โ ซโ ชcircle spaceโ ฌโ ฌ โ ซโ ชrectangle spaceโ ฌโ ฌ โ ซโ ชtriangle spaceโ ฌโ ฌ โ ซโ ชfrom list above to select: 2โ ฌโ ฌ
โ ซโ ช1- Calculateโ ฌโ ฌ โ ซโ ช2- Calculateโ ฌโ ฌ โ ซโ ช3- Calculateโ ฌโ ฌ โ ซโ ชEnter numberโ ฌโ ฌ
โ ซโ ฆ โ ชCalculating rectangle spaceโ ฌโ ฌ โ ซโ ชEnter Rectangle width: 5โ ฌโ ฌ โ ซโ ชEnter Rectangle height: 3โ ฌโ ฌ โ ซโ ชS = 15โ ฌโ ฌ
โ ซโ ช .12โ ฌุงู ุชุจ ุจุฑู ุงู ุฌุง ู ู ู ุชุงุจุน ู ุคุฎุฐ ู ุณู ุทุง ู โ ฌ โ ซู ู ุซู ุงุฑุชู ุงุน ู ุซู ุซ ุซ ู ู ู ุทุจุนู ุจุงู ุดู ู ุงู ุชุงู ู โ ช:โ ฌโ ฌ โ ซ*โ ฌ โ ซ*โ ฌ โ ซ*โ ฌ โ ซ*โ ฌ โ ซ*โ ฌ
โ ซ*โ ฌ โ ซ* *โ ฌ โ ซ* * *โ ฌ โ ซ* * * *โ ฌ
โ ซ*โ ฌ โ ซ* *โ ฌ โ ซ* * *โ ฌ โ ซ* * * *โ ฌ โ ซู ู ู ุฐุง ุงู ู ุซุงู ุงุงู ุฑุชู ุงุน โ ช h = 5โ ฌู ู ุณุทุฑ ู ุญู ู โ ช) -1โ ฌุฑู ู ุงู ุณุทุฑ(*โ ช 3โ ฌู ุฌู ุฉโ ช.โ ฌโ ฌ โ ซุงุทุจุน ู ุฑุงุบุงุช ุญ ู ุชู ุฃู ู ู ู ุฌู ุฉ ู ู ุงู ุณุทุฑ ุซ ู ู ุงุณุชุฎุฏู ุงู ุนุจู ู ุฉ ุงู ุณุงุจู ุฉ ู ุทุจุงุนุฉ ุนุฏุฏ ุงู ู ุฌู ุงู ู ุทู ู ุจุฉ ู ู ู ู โ ฌ โ ซุณุทุฑโ ช.โ ฌโ ฌ
โ ซโ ช87โ ฌโ ฌ
القسم الثاني ِ مِ ّإل بست ٍة أخي لن تنال الع َ اجتُاد وبمغةٌ وحرص و ٌ ٌ ذكاءٌ
يك سأَُّبِ َ وصحبةُ
ِ ببيان عن تفصيمُا ٍ ِ زمان وطول أستاذ ُ اإلمام الشافعي
88
الفصل التاسع:
المصفوفة هً سلسلة من العناصر ذات النوع نفسه محفوظة فً الذاكرة بشكل متتالً بحٌث ٌمكن الوصول إلى أي عنصر بذكر اسم المصفوفة متبوعا بالدلٌل .الشكل العام للتصرٌح عن المصفوفات هو
;]type name [elements :type
نوع البٌانات الخاص بالمصفوفة.
:nameاسم الصفوفة.
:elementsعدد العناصر.
فمثبل ٌمكن أن نخزن 5قٌم من النوع intدون الحاجة إلى التصرٌح عن خمسة متغٌّرات بؤسماء مختلفة وذلك باستخدام المصفوفات كما ٌلً:
; ]int array[5
أي المصفوفة arrayتحوي خمس قٌم صحٌحة ) ( integerكما فً الشكل السابق.
مالحظة :عند التصرٌح عن المصفوفة فً لغة ٌ C++جب أن ٌكون عدد العناصر قٌمة ثابتة حٌث إن المصفوفات هً حجرات ذاكرة ستاتٌكٌة ٌجب أن ٌُعطى حجم هذه الحجرات للمترجم compilerلٌحدد كم من الذاكرة ٌجب أن ٌحجز للمصفوفة قبل تنفٌذ البرنامج.
ٌمكن تعببة المصفوفة )إسناد القٌم لعناصرها ( كما ٌلً ;}int array[5]={1,3,4,2,7 وٌمكن فً هذه الحالة تجاوز المبلحظة السابقة أي ٌمكن كتابة ;}int array[]={1,3,4,2,7 عندما نصرح عن المصفوفات داخل التوابع وال نضع قٌم لعناصرها فإن قٌم العناصر ستبقى عشوابٌة حتى نضع قٌم لهذه العناصر ,وعندما نصرح عن المصفوفات خارج أي تابع فإن قٌم العناصر تكون صفرٌة.
89
التعامل مع المصفوفات فً أي جزء من البرنامج تكون فٌه المصفوفة مربٌّة )راجع فقرة المدى( ٌمكن أن نصل إلى عناصرها للقراءة أو للتعدٌل على أيّ عنصر منها كما ٌلً: اسم المصفوفة ] الدلٌل [
]name[index
من المثال السابق تكون العناصر كما فً الشكل:
فإذا أردنا إسناد قٌمة العنصر الثالث للمتحول aنكتب
; ]a=array[2
ولِوضع القٌمة 10فً العنصر األول نكتب
; array[0]=10
لؤلقواس المربعة استخدامان مختلفان األول لتحدٌد حجم المصفوفة عند التصرٌح عنها ,والثانً لتحدٌد دلٌل العنصر المراد الوصول إلٌه من المصفوفة التصرٌح عن مصفوفة جدٌدة ٌبدأ بتحدٌد نوعها // الوصول إلى العنصر األول من المصفوفة //
;]int array[5 ;array[0] = 10
هناك عبارات أخرى صحٌحة مثل ;array [0] = a ;array [a] = 75 ;]b = array [a+2 ;array [array [a]] = array [2] + 5
مثال 12206
// arrays example >#include <iostream ;using namespace std ;}int m[] = {16, 2, 77, 40, 12071 ;int i,sum=0 )( int main { ) for ( i=0 ; i<5 ; i++ { ;]sum+= m[i } ;cout <<sum ;return 0 }
الخرج هو مجموع عناصر المصفوفة m 8:
المصفوفات المتعددة األبعاد ٌمكن أن توصف المصفوفات المتعددة األبعاد بؤ ّنها مصفوفات لمصفوفات فالمصفوفة ثنابٌة البعد ٌمكن تصورها على أ ّنها جدول ثنابً البعد لبٌانات من نوع واحد.
تمثل aمصفوفة ثنابٌة البعد مإلفة من 3أسطر و 5أعمدة من النوع intتع ّرف كما ٌلً : ;]int a[3][5 وللوصول إلى العنصر الواقع فً السطر الثانً والعمود الرابع نكتب ]a[1][3
) تذ ّكر أنّ أدلّة المصفوفة تبدأ دابما بـ ( 0 المصفوفات المتعددة األبعاد ال تقتصر على دلٌلٌن) بعدٌن( فقط بل ٌمكن أن تحوي أدلة بحسب الحاجة ,لك ّننا نادرا ما نحتاج أكثر من 3أبعاد حٌث تكون كمٌة الذاكرة المطلوبة لتخزٌن هذه المصفوفات كبٌرة جدّا فمثبل ;]char century [100][365][24][60][60 هذه المصفوفة تحجز فً الذاكرة متغٌّر من نوع charلكل ثانٌة فً القرن أي تحجز حوالً 3ملٌارات باٌت إذا صرحنا عن هذه المصفوفة فإ ّنها ستستهلك حوالً 3جٌغا من الذاكرة .RAM المصفوفات المتعددة األبعاد هً مجرد تبسٌط لمصفوفة من بعد واحد حٌث المصفوفتان التالٌتان متكافبتان )int a [15]; (3 * 5 = 15
;]int a [3][5
والشٌفرتان التالٌتان متكافبتان أٌضا
91
// pseudo-multidimensional array >#include <iostream ;using namespace std
// multidimensional array >#include <iostream ;using namespace std
#define WIDTH 5 #define HEIGHT 3
#define WIDTH 5 #define HEIGHT 3
;]int a [HEIGHT * WIDTH ;int n,m
;]int a [HEIGHT][WIDTH ;int n,m
)( int main { )for (n=0;n<HEIGHT;n++ )for (m=0;m<WIDTH;m++ { ;)a[n*WIDTH+m]=(n+1)*(m+1 } ;return 0 }
)( int main { )for (n=0;n<HEIGHT;n++ )for (m=0;m<WIDTH;m++ { ;)a[n][m]=(n+1)*(m+1 } ;return 0 }
كبل البرنامجٌن ٌحجزان ذاكرة للمصفوفة aكما فً الجدول التالً :
استخدمنا #defineلٌصبح التعدٌل البلحق على البرنامج أسهل فلو أردنا أن تكون قٌمة البعد HEIGHT 4بدال من 2نكتب #define HEIGHT 4بدال من #define HEIGHT 3 وذلك أبسط من تعرٌف المصفوفة بثوابت عددٌة ) ;] ( int a[3][5ث ّم تعدٌل 3إلى 4فً كل مرّ ة تذكر فٌها المصفوفة
فً البرنامج. كما ٌمكن أن نسند قٌم لعناصر المصفوفة أثناء التصرٌح كما ٌلً : ;}}int a[3][5]={{1,2,3,4,5},{2,4,6,8,10},{3,6,9,12,15 حٌث إنّ العناصر المحصورة بٌن األقواس الداخلٌة هً عناصر السطر األول والثانً والثالث بالترتٌب أمّا إذا كتبنا ;}}int a[3][5]={{1,3,4,5},{10},{12,15 فإنّ باقً عناصر المصفوفة تكون أصفارا كما فً الجدول المبٌن :
92
المصفوفات كمعامالت(وسطاء) للتوابع نحتاج أحٌانا أن نم ّرر مصفوفة كمعامل لتابع ما .فً لغة C++ال ٌمكن تمرٌر مجموعة حجرات ذاكرة بالقٌمة كمعامل لتابع ما ,وبالتالً ال ٌمكن تمرٌر كامل المصفوفة ,ولكن ٌمكن تمرٌر عنوانها الذاكري. ولكً تصبح المصفوفات معامبلت ٌجب علٌنا عند التصرٌح عن التابع المراد التعامل معه أن نضع نوع البٌانات للمصفوفة المراد استقبالها واسم للمصفوفة داخل التابع ث ّم أقواس مربعة فارغة فمثبل التابع )][void procedure (int arg ٌقبل مصفوفة من النوع intوسٌسمٌها argولنمرر مصفوفة لهذا التابع نصرح عنها ;]int myarray [40 ث ّم نستدعً التابع كما ٌلً
;)procedure (myarray
مثال 5 10 15 2 4 6 8 10
// arrays as parameters >#include <iostream ;using namespace std { )void printarray(int arg[], int length )for (int n=0; n<length; n++ ;" " << ]cout << arg[n ;"cout << "\n } )( int main { ;}int firstarray[] = {5, 10, 15 ;}int secondarray[] = {2, 4, 6, 8, 10 ;)printarray (firstarray,3 ;)printarray (secondarray,5 ;return 0 }
كما ترى فإنّ المعامل األول للتابع printarrayهو )][ٌ (int argقبل أي مصفوفة من النوع intأٌا كان طولها ,أمّا المعامل الثانً فهو طول المصفوفة المراد تمرٌرها وهذا ٌعطً الحلقة forشرط التوقف. عند التصرٌح عن التابع ٌمكن أٌضا أن نم ّكنه من أن ٌستقبل المصفوفات المتعددة األبعاد وٌكون التصرٌح عن التابع الذي ٌقبل المصفوفة ;)]void procedure (int myarray[ ][3 ثنابٌة األبعاد ;)]void procedure (int myarray[ ][3][4 وثبلثٌة األبعاد 93
الحظ أنّ القوس األول فارغ أمّا باقً األقواس فٌجب أن نحدّد عمقها ألنّ المترجم ٌجب أن ٌحدد خبلل التابع ما هً قٌمة كل بعد إضافً. عندما تمرّ ر المصفوفات األحادٌة أو المتعددة األبعاد كمعامبلت للتوابع تشكل مصدرا شابعا لؤلخطاء عند المبرمجٌن قلٌلً الخبرة ,ننصح هنا بقراءة فصل المإ ّ شرات لفهم أفضل آللٌة عمل المصفوفات.
األعداد العشوائٌة
هناك العدٌد من التطبٌقات البرمجٌة الشابعة التً تحتاج إلى المحاكاة كاأللعاب والدراسات االحتمالٌة واالحصابٌة. ٌمكن أن نولد األعداد العشوابٌة فً لغة C++باستخدام التابع )( randالموجود فً المكتبة القٌاسٌة > <cstdlibلذلك ٌجب أن نضمّنها فً البرنامج. ٌولد التابع )( randأرقاما صحٌحة موجبة ( )unsigned integerبٌن 0و RAND_MAXالذي هو ثابت رمزي معرف فً المكتبة القٌاسٌة تكون قٌمته 32767على األقل. لكً نحدد مجال لؤلعداد التً سٌتم تولٌدها نستخدم العبلقة
;number = shiftingValue + rand() % scalingFactor :numberالعدد المولّد :shiftingValue .اإلزاحة :scalingFactor .طول مجال التولٌد. مثال: إنّ القٌم المحتملة للمتغٌّر numberهً ضمن المجال ].[1,6
;number = 1 + rand() % 6
كل مرّ ة ٌت ّم فٌها تنفٌذ البرنامج ٌت ّم تولٌد نفس األعداد لذلك ٌوجد تابع فً المكتبة القٌاسٌة اسمه )(ٌ srandقوم بتغٌٌر سلسلة األرقام عند كل تنفٌذ للبرنامج وٌستقبل هذا التابع قٌمة من النوع unsigned integerولكً نضمن تغٌّر القٌمة المرسلة إلى srandنستخدم التابع )( timeكالتالً: ;) ) srand( time( 0 ) ٌ time( 0قرأ الوقت عند التنفٌذ بالثوانً وٌحوّ له إلى .unsigned integer التابع )( timeموجود فً المكتبة > <ctimeالتً ٌجب أن نضمّها إلى البرنامج.
مثال: >#include <iostream >#include <cstdlib >#include <ctime ;using namespace std )( int main { ;int num,guess,guessNum ;"cout<<"\tguessing game\n\n ;))srand(time(0 ;num=1+rand()%100 ;" cout<<"enter your guess between 1 and 100: )for(guessNum=0;guess!=num;guessNum++ { ;cin>>guess )if(guess<num ;" cout<<"your guess is too low!. try again: )if(guess>num ;" cout<<"your guess is too high!. try again: }
94
cout<<"congratulations. you guessed it!!!. " <<"\nyou tried "<<guessNum<<" times to guess it\n"; return 0; } guessing game enter your guess between 1 and 100: your guess is too high!. try again: your guess is too low!. try again: your guess is too high!. try again: your guess is too high!. try again: congratulations. you guessed it!!!. you tried 5 times to guess it
95
50 25 37 31 28
: ذات النوع الصحٌح قم بطباعتها ث ّم اطبع مجموع عناصرهاA لتكن لدٌنا المصفوفة-1 A= [ 5, 6, 1, 9, 12, 4, 7 ]
#include <iostream> using namespace std; int main() { int A[]={5,6,1,9,12,4,7}; int sum=0; for(int i=0;i<7;i++) { cout<<A[i]<<" "; sum+=A[i]; //sum =sum+A[i]; } cout<<"\nsum= "<<sum<<endl; return 0; }
. اكتب برنامجا لحساب سلسلة فٌبوناكسً بطرٌقة تكرارٌّة-2
#include<iostream> using namespace std; int f[1000]; int fib(int n) { f[0] = 0; f[1] = 1; for(int i=2; i<=n;i++) f[i] = f[i-1]+f[i-2]; return f[n]; } int main() { int n ; cout<< "Enter n: "; cin>> n; cout<< "\nfib(" << n << ") = " << fib(n) << endl; }
ث ّم ٌقوم بالبحث عنV أرقام صحٌحة إلى مصفوفة وعدد10 اكتب برنامجا ٌطلب من المستخدم أن ٌدخل-3 ّ موجودا فٌهاV " إذا كانV is in the array" ضمن عناصر المصفوفة المدخلة وٌطبعV وإال فإ ّنه ٌطبع ."V is not in the array" 96
#include <iostream> using namespace std; int main() { int arr[10],V,i; bool found=false; cout<<"enter 10 numbers please!\n"; for(i=0;i<10;i++) { cout<<"number"<<i+1<<"= "; cin>>arr[i]; } cout<<"enter V: "; cin>>V; for(i=0;i<10;i++) if(arr[i]==V) { found=true; break; } if(found) //same as if(found==true) cout<<"V is in the array\n"; else cout<<"V is not in the array\n"; return 0; }
: ًث ّم عمل ماٌل اكتب برنامجا لقراءة مصفوفة ثنابٌة األبعاد-4 .print() طباعة المصفوفة بشكل مناسب باستخدام تابع .( الصفرٌة, السالبة, طباعة عدد العناصر) الموجبة . طباعة عدد العناصر الزوجٌة والفردٌة . طباعة عناصر القطر الربٌسً ث ّم عناصر القطر الثانوي
#include <iostream> using namespace std; void print(int a[][4]) { int i,j; for(i=0;i<4;i++) { for(j=0;j<4;j++) cout<<a[i][j]<<"\t"; cout<<"\n\n"; } } int main() {
97
int X[4][4],i,j; int positives=0,negatives=0,zeros=0; int even=0,odd=0; for(i=0;i<4;i++) for(j=0;j<4;j++) { cout<<"X["<<i+1<<"]["<<j+1<<"]= "; cin>>X[i][j]; if(X[i][j]>0) positives++; if(X[i][j]<0) negatives++; if(X[i][j]==0) zeros++; if(X[i][j]%2==0) even++; if(X[i][j]%2!=0) odd++; } cout<<"\n"; print(X);//printing X cout<<"\nnumber of positive elements="<<positives; cout<<"\nnumber of negative elements="<<negatives; cout<<"\nnumber of zeroth elements="<<zeros; cout<<"\nnumber of even elements="<<even; cout<<"\nnumber of odd elements="<<odd; cout<<"\nleading diagonal: "; for(i=0;i<4;i++) cout<<X[i][i]<<"\t"; cout<<"\ncross diagonal: "; for(i=0;i<4;i++) { for(j=0;j<4;j++) if(i+j==4-1) cout<<X[i][j]<<"\t"; } cout<<endl; return 0; }
اكتب برنامجا ٌقوم بجمع مصفوفتٌن ثنابٌتً األبعادعلما أن شرط الجمع هو أن ٌكون للمصفوفتٌن نفس-5 .األبعاد
// program to add matrix to another one #include <iostream> using namespace std; int main() { int a[10][10],b[10][10],c[10][10]; int i,j,m,n; cout<<"number of rows=";cin>>m; cout<<"number of columns=";cin>>n; for(i=0;i<m;i++) for(j=0;j<n;j++)
98
{ cout<<"a["<<i+1<<"]["<<j+1<<"]=";cin>>a[i][j]; cout<<"b["<<i+1<<"]["<<j+1<<"]=";cin>>b[i][j]; c[i][j]=a[i][j]+b[i][j]; } for(i=0;i<m;i++) { for(j=0;j<n;j++) cout<<a[i][j]<<" "; cout<<"\n"; } cout<<"\n +\n\n"; for(i=0;i<m;i++) { for(j=0;j<n;j++) cout<<b[i][j]<<" "; cout<<"\n"; } cout<<"\n =\n\n"; for(i=0;i<m;i++) { for(j=0;j<n;j++) cout<<c[i][j]<<" "; cout<<"\n"; } return 0; }
اكتب برنامجا ٌقوم بضرب مصفوفتٌن ثنابٌتً األبعادعلما أن شرط الضرب هو أن ٌكون عدد أعمدة-6 .المصفوفة األولى ٌساوي عدد أسطر المصفوفة الثانٌة
//matrix multiplication #include<iostream> using namespace std; #define M 20 int a[M][M],b[M][M],c[M][M];//all arrays' elements equal zero void main() { int ma,na,mb,nb,i,j,k; /*ma=number of A rows,na=number of A columns, mb=number of B rows,nb=number of B columns, i,j,k:counters */ cout<<"enter dimensions of A(ma,na): ";cin>>ma>>na; cout<<"enter dimensions of B(mb,nb): ";cin>>mb>>nb; if(na!=mb) cout<<"verify multiplication condition na=mb\n"; else { cout<<"enter A elements\n";//reading A elements for(i=0;i<ma;i++) for(j=0;j<na;j++) { cout<<"a["<<i+1<<"]["<<j+1<<"]= ";cin>>a[i][j];}
99
cout<<"enter B elements\n";//reading B elements for(i=0;i<mb;i++) for(j=0;j<nb;j++) { cout<<"b["<<i+1<<"]["<<j+1<<"]= ";cin>>b[i][j];} for(i=0;i<ma;i++)//multiplication for(j=0;j<nb;j++) for(k=0;k<na;k++) c[i][j]+=(a[i][k]*b[k][j]); cout<<"the result C=\n\n"; for(i=0;i<ma;i++) {for(j=0;j<nb;j++) cout<<c[i][j]<<"\t"; cout<<"\n\n";} } }
( لٌقومprint) ( تحوي أسماء األشهر ث ّم مرر هذه المصفوفة إلى تابعstring) عرّ ف مصفوفة من النوع-8 .بطباعتها
#include<iostream> #include<string> using namespace std; void print(string m[],int n) { for(int i=0;i<n;i++) cout<<m[i]<<"\n"; } int main() { string months[12]={"January","February","March" ,"April","May", "June" ,"July","August","September" ,"October","November","December"}; print(months,12); return 0; }
9:
-1أوجد األخطاء فً كل من العبارات التالٌة: بفرض ; } int b[ 10 ] = { 0 ) for ( int i = 0; i<= 10; i++ ;b[ i ] = 1
)a
;] int a[ 3 بفرض ;cout<<a[1]<<" "<<a[2]<<" "<<a[3]<<endl
)b
;} double f[ 3 ] = { 1.1, 10.01, 100.001, 1000.0001
)c
;] double d[ 2 ][ 10 ;d[ 1, 9 ] = 2.345
)d
بفرض
-2امؤل الفراغات التالٌة : (aأسماء العناصر األربع للمصفوفة ( int p[4]; ) pهً ______ و ______ و ______ و ______. (bتسمٌة المصفوفة بتحدٌد نوعها وعدد عناصرها ٌدعى _______ المصفوفة. (cاسم العنصر الواقع فً السطر 3والعمود 5فً المصفوفة dهو ______. (dالمصفوفة المإلفة من 4أسطر و 5أعمدة تحوي ______ عنصرا.
-3اكتب التعلٌمة أو التعلٌمات البلزمة للقٌام بالمهام التالٌة : (aصرّ ح عن متغٌّر ثابت باسم arraySizeوأعطه القٌمة .10 (bصرّ ح عن المصفوفة fractionsبعدد عناصر arraySizeونوع doubleوأعط عناصرها القٌمة .1 (cضع القٌمة 1.667فً العنصر التاسع والقٌمة 3.333فً العنصر السابع. (dاطبع المصفوفة باستخدام حلقة .for -4رتب المصفوفة التالٌة تصاعدٌا ث ّم تنازلٌا واطبعها فً الحالتٌن ]A = [1,5,4,3,7,2,9,0 -5اكتب برنامجا ٌطلب من المستخدم إدخال مصفوفتٌن Aو ) Bمن النوع (integerكل منهما مكونة من 10عناصر ٌ ,جب على البرنامج أن ٌضم المصفوفة Bإلى نهاٌة المصفوفة Aوٌضع الناتج فً المصفوفة Cالمإلفة من 20عنصر ث ّم ٌطبع المصفوفة .C -6اكتب برنامجا ٌطلب من المستخدم إدخال مصفوفة ) (integerمن 10عناصر ث ّم ٌطبع البرنامج المصفوفة تصاعدٌة " " the array is growingأو تنازلٌة ""the array is decreasing أو ثابتة " "the array is constantأو تصاعدٌة وتنازلٌة "the array is growing and "decreasing. :1
-7اكتب برنامجا ٌم ّكن المستخدم من إدخال عدد الطبلب nوأسمابهم namesودرجاتهم marksفً مقرر ما ث ّم ٌطبع أسماء الطبلب حسب درجاتهم فً المقرر وبترتٌب تنازلً. -8اكتب برنامجا ٌقوم بجمع مصفوفتٌن ثنابٌتً األبعاد علما أن شرط الجمع هو أن ٌكون للمصفوفتٌن نفس األبعاد باستخدام التوابع) .التمرٌن محلول فً التمارٌن المحلولة بدون استخدام التوابع(. -9اكتب برنامجا ٌقوم بتنفٌذ اللعبة التالٌة لعبة ) ورقة – مقص – حجر ( تحتاج هذه اللعبة إلى العبٌن فقط حٌث ٌخفً كل منهما ٌده وٌختار أحد الخٌارات الثبلث وٌكون الرابح وفق الجدول التالً: الخٌار األول ورقة حجر مقص
الخٌار الثانً حجر مقص ورقة
النتٌجة الورقة تغطً الحجر لذلك تربح نقطة الحجر ٌكسر المقص لذلك ٌربح نقطة المقص ٌقص الورقة لذلك ٌربح نقطة
:2
الفصل العاشر:
تم ّكننا السبلسل من التعامل مع النصوص سواء منها الكلمات أو الجمل أو األسماء. .. السلسلة مإلفة من تتابع من العناصر ذات النوع charحٌث إنّ كل عنصر ٌمثل حرف فً السلسلة .فمثبل المصفوفة )سلسلة الرموز( التالٌة : ;]char str [20 ٌمكن أن تخزن سلسلة مإلفة من 15حرف كما فً الشكل
لٌس ضرورٌا أن نمؤل كل عناصر السلسلة فٌمكن أن تحوي السلسلة فً نقطة ما من البرنامج الكلمة ""Hello التً تمؤل 5خانات أو العبارة " "Hello Worldالتً تمؤل 12خانة. عند نهاٌة السلسلة المخزنة فً كبل الحالتٌن نصل إلى الرمز nullالذي ٌمكن أن ٌكتب 0أو ' ' \0
أما العناصر الواقعة فً المنطقة الرمادٌة فقٌمها غٌر محددة.
التعامل مع السالسل
بما أنّ السبلسل هً مصفوفات طبٌعٌة فإ ّنها تخضع لنفس قواعد المصفوفات فإذا أردنا مثبل أن نضع القٌم فً السلسلة أثناء التصرٌح نكتب : ;} 'char mystring[6] = { 'H', 'e', 'l', 'l', 'o', '\0 أو ;} 'char mystring[ ] = { 'H', 'e', 'l', 'l', 'o', '\0 ولكن هناك طرٌقة أخرى لعمل ذلك وهً: ;"char mystring [ ] = "Hello حٌث إنّ السبلسل المحصورة بعبلمات اقتباس مزدوجة ٌضاف إلى نهاٌتها الثابت nullبشكل آلً. إنّ إسناد الثوابت النصٌة مثل " "Helloللسبلسل صحٌح فقط أثناء التصرٌح عن السلسلة )المصفوفة( لذلك فالعبارات التالٌة غٌر صحٌحة: ;"mystring = "Hello ;"mystring[] = "Hello ;} 'mystring = { 'H', 'e', 'l', 'l', 'o', '\0
:3
السبب فً ذلك ٌعود إلى أنّ المصفوفة هً عبارة عن مإ ّ شر ثابت ٌشٌر إلى كتلة ذاكرة محجوزة وبسبب هذا الثبات )فً قٌمة المإ ّ شر( فبل ٌمكن أن نسند أٌّة قٌمة للمصفوفة بح ِّد ذاتها ولكن ٌمكن إسناد قٌمة أليّ عنصر من عناصر هذه المصفوفة. لذلك فإنّ الطرف األٌسر لئلسناد ٌمكن أن ٌكون فقط عنصر من مصفوفة ولٌس مصفوفة كاملة. إذا ٌمكن أن نكتب : ;'mystring[0] = 'H ;'mystring[1] = 'e ;'mystring[2] = 'l ;'mystring[3] = 'l ;'mystring[4] = 'o ;'mystring[5] = '\0 ال تبدو هذه طرٌقة عملٌة لذلك سنستخدم توابع جاهزة مثل التابع strcpyالمعرّ ف فً المكتبة cstring ) (stringوٌُستد َعى بالطرٌقة التالٌة: ;)strcpy (string1, string2 هذا التابع ٌقوم بنسخ محتوى string2وٌضعه فً string1 ٌ string2مكن أن ٌكون مصفوفة أو مإ ّ شرا أوسلسلة ثابتة. إذا إلسناد " "Helloإلى السلسلة mystringنكتب: ;)"strcpy (mystring, "Hello مثال Basil
// setting value to string >#include <iostream ;using namespace std >#include <string )( int main { ;]char MyName[20 ;)"strcpy (MyName,"Basil ;cout << MyName ;return 0 }
استخدمنا المكتبة > <stringلنتمكن من التعامل مع التابع strcpy ٌمكن أن نكتب التابع setstringالمإدي نفس الوظٌفة دون االستعانة بـ strcpy Basil
// setting value to string >#include <iostream ;using namespace std )][void setstring(char Out[],char In { ;int n=0 { do ;]Out[n] = In[n ;)'} while (In[n++] != '\0 } )( int main { ;]char MyName [20 ;)"setstring (MyName,"Basil ;cout <<MyName ;return 0 }
:4
هناك طرٌقة أخرى تعتمد على تعلٌمة اإلدخال cinفً هذه الحالة ٌت ّم إدخال السلسلة من قبل المستخدم أثناء تنفٌذ البرنامج حٌث نستخدم هنا التابع getlineحسب الشكل العام ;)'cin.getline ( char buffer[], int length, char delimiter = ' \n :bufferهو المصفوفة التً سٌ َّ ُخزنُ فٌها الدخل. :lengthهو الطول األعظمً للمصفوفة buffer ّ :delimiterهو الرمز الذي ٌحدّد نهاٌة إدخال المستخدم )إذا لم نضع هذا المعامل فإنه ٌكون بشكل افتراضً رمز السطر الجدٌد ' '\nأي عندما نضغط ( enter فمثبل ٌقوم هذا البرنامج بتكرار ماتكتبه على لوحة المفاتٌح ?What's your name Sameer Hello Sameer. Which is your favourite book? The Holy Qura’an I like The Holy Qura’an too.
// cin with strings >#include <iostream ;using namespace std )( int main { ;]char mybuffer [100 ;"cout << "What's your name?\n ;)cin.getline (mybuffer,100 ;"cout << "Hello " << mybuffer << ".\n ;"cout << "Which is your favourite book?\n ;)cin.getline (mybuffer,100 ;"cout << "I like " << mybuffer << " too.\n ;return 0 }
عندما استخدمنا cin.getlineألول مرّ ة كانت قٌمته ّ تخزن االسم Sameerفً المصفوفة mybufferأما فً المرّ ة الثانٌة فإنّ التابع ٌقوم بالكتابة فوق المحتوى األول للمصفوفة أي ٌخزن The Holy Qura’anفً المصفوفة. مالحظة ٌ :مكن إدخال السبلسل باستخدام التعلٌمة ; cin >> mybuffer هذه الطرٌقة مقبولة لكنها تسمح لنا بإدخال الكلمات فقط و ال تستقبل من الجملة الحاوٌة على فراغات إال أول كلمة ,كما ال ٌمكن تحدٌد طول المصفوفة mybufferالتً سٌدخلها المستخدم أي إذا أدخل عددا من األحرف أكبر من طول المصفوفة المحجوزة سٌتوقف تنفٌذ البرنامج لذلك من األفضل استخدام cin.getlineعند التعامل مع السبلسل.
:5
الفصل احلاد
شصر:
إنّ ذاكرة الحاسوب ماهً ّإال تتابع من خبلٌا حجم كل منها واحد باٌت ,ولكل واحدة من هذه الخبلٌا عنوان ممٌز حٌث ٌتولى نظام التشغٌل عنونة الذاكرة بؤرقام متتابعة. المإ ّ شر هو متغٌّر كسابر المتغٌّرات ولكنه ٌختلف عنها فٌما ٌختزنه فهو ال ٌختزن البٌانات العادٌة كاألرقام والرموز وإ ّنما ٌختزن عنوان المتغٌّر الذي ٌشٌر إلٌه.
معامل العنوان ( & ) ّ سٌخزن فً إحدى الخبلٌا المتاحة فً الذاكرة بشكل آلً من قبل المترجم ونظام عندما نصرّ ح عن متغٌّر فإ ّنه التشغٌل ,فإذا أردنا معرفة مكان تخزٌن هذا المتغٌّر نسبق اسم المتغٌّر بالرمز &. مثبل التعلٌمة ; a = &bستضع عنوان المتغٌّر bفً المتغٌّر .a ّ مؤشراًً )مثل المتغٌّر aفً السطر السابق(. إنّ المتغٌّر الذي ٌحوي عنوان متغٌّر آخر ٌدعى
معامل المرجع ( * ) إذا سبقنا المإ ّشر aبمعامل المرجع * أي إذا كتبنا *aفإنّ العبارة ; c = *aتعنً ضع القٌمة التً ٌُشٌ ُر إلٌها المإ ّ شر aفً المتغٌّر .c
;a = &b ;c = *a
ٌجب االنتباه إلى الفرق بٌن العبارتٌن c = a; // c == 1176 c = *a; // c = =25 مما سبق تكون العبارات التالٌة صحٌحة b == 25 &b == 1776 a == 1776 *a == 25 *a == b :6
التصرٌح عن المؤ ّ شرات الشكل العام للتصرٌح هو ;type * pointer_name شر ولٌس نوع المإ ّ :typeهو نوع البٌانات التً سٌشٌر إلٌها المإ ّ شرذاته :pointer_nameاسم المإ ّ شر . أمثلة
;int * number ;char * character ;float * greatnumber شرات كل منها ٌشٌر إلى نوع مختلف من البٌانات مع ذلك فإنّ ك ّل واحد من هذه المإ ّ لدٌنا ثبلثة مإ ّ شرات ٌحجز نفس الحجم فً الذاكرة بحسب نظام التشغٌل أ ّما البٌانات التً ُتشٌر إلٌها هذه المإ ّ شرات لها حجوم مختلفة فً الذاكرة كما أنها من أنواع مختلفة. مثال 0 a=10 , b=20
// my first pointer >#include <iostream ;using namespace std )( int main { ;int a = 5, b = 15 ;int *ptr ;ptr= &a ;*ptr = 10 ;ptr = &b ;*ptr = 20 ;cout<<"a="<<a<<" , b="<<b ;return 0 }
الحظ أنه تم تعدٌل قٌم aو bبشكل غٌر مباشر حٌث جعلنا المإ ّ شر ٌ ptrشٌر إلى aعن طرٌق الرمز & ث ّم أسندنا القٌمة 10إلى ماٌشٌر إلٌه المإ ّ شر ptrوكذلك األمر بالنسبة لـ .b ّ كما ٌمكن أن ٌؤخذ المإ ّ شر خبلل البرنامج عناوٌن مختلفة حٌث استخدمنا المإشر ptrلٌشٌر إلى a ث ّم إلى .b مثال 2 a=10 , b=20
// more pointers >#include <iostream ;using namespace std )( int main { ;int a = 5, b = 15 ;int *p1, *p2 = p1عنوان // a ;p1 = &a ;p2 = &b = p2عنوان // b ;*p1 = 10 اٌمّ١خ اٌز٠ ٟش١ش ئٌٙ١ب // 12=p1 ;*p2 = *p1 القٌمة التً ٌشٌر إلٌها = p2القٌمة التً ٌشٌر إلٌها // p1 // p1 = p2 ;p1 = p2 القٌمة التً ٌشٌر إلٌها // 32 = p1 ;*p1 = 20 ;cout << "a=" << a << " , b=" << b ;return 0 }
:7
المؤ ّ شرات والمصفوفات إنّ المصفوفة تشبه المإ ّ شر إلى ح ّد كبٌر فعندما نصرح عن مصفوفة فإ ّننا نضع فً الذاكرة عنوان أول عنصر ّ ّ من عناصرها كما أ ّننا عندما نصرح عن مإشر فإنه ٌشٌر إلى أول عنصر لذلك فهما متشابهان. لنفرض التصرٌحٌن التالٌٌن: ;]int numbers [20 ;int * p إنّ اإلسناد ; p = numbersصحٌح ألنّ pو numbersمتكافبان ولهما نفس الخصابص ,االختبلف الوحٌد هو أ ّننا نستطٌع أن نعطً قٌمة مختلفة للمإ ّ شر pفً حٌن أنّ numbersسٌشٌر دوما إلى أول عنصر من شر عادي إلى المتغٌّرات أ ّما numbersفهو مإ ّ العشرٌن عنصر .لذلك فإنّ pهو مإ ّ شر ثابت ) اسم المصفوفة هو مإ ّ شر ثابت (. أمّا اإلسناد ; numbers = pفلٌس صحٌحا ألنّ numbersمصفوفة )مإ ّ شر ثابت( وال ٌمكن إسناد قٌمة للمإ ّ شر الثابت. مثال 3 10, 20, 30, 40, 50,
// more pointers >#include <iostream ;using namespace std )( int main { ;]int numbers[5 ;int * p ;p = numbers; *p = 10 ;p++; *p = 20 ;p = &numbers[2]; *p = 30 ;p = numbers + 3; *p = 40 ;p = numbers; *(p+4) = 50 )for (int n=0; n<5; n++ ;" cout << numbers[n] << ", ;return 0 }
فً فصل المصفوفات استخدمنا األقواس المربعة للتعامل مع عناصر المصفوفة ,هناك طرٌقة مكافبة باستخدام شرات كما ٌلً )إذا كان المإ ّ المإ ّ شر ٌ pشٌر إلى المصفوفة :(a ]a[0 ]a[1 ]a[2 ... ]a[i . .
*p )*(p+1 )*(p+2 ... )*(p+i . .
فإذا أردنا وضع القٌمة 1فً العنصر الخامس للمصفوفة aفهناك طرٌقتان متكافبتان ;a[5] = 0 ;*(p+5) = 0
:8
تبدئة المؤ ّ شرات ٌمكن عند التصرٌح عن المإ ّ شرات جعلها تشٌر إلى المتغٌّر المراد أي ;int number ;int * p = &number وهذا ٌكافا ;int number ;int * p ;p = &number شرات ولٌس إسناد قٌم المتغٌّرات للمإ ّ شرات نسند فقط عناوٌن المتغٌّرات للمإ ّ فً المإ ّ شرات. فبل ٌجوز فً أي مكان عدا مكان التصرٌح أن نكتب ; *p = &numberألنّ *pهو قٌمة ماٌشٌر إلٌه المإ ّ شر وال ٌجوز أن نسند إلٌها عنوان المتغٌّر. أمّا فً حالة المصفوفات فإنّ المترجم ٌسمح لنا بؤن نسند الثابت الذي سٌشٌر إلٌه المإ ّ شر أثناء التصرٌح عن المإ ّ شر )هنا الثابت هو سلسلة رموز(: ;"char * p = "hello فً هذه الحالة ت ّم حجز حجم ثابت من الذاكرة لتخزٌن السلسة " "helloوت ّم جعل المإ ّ شر ٌ pشٌر إلى أول رمز ) (charلمجموعة الحجرات الذاكرٌّة التً ت ّم حجزها أي أنّ ٌ pشٌر إلى الحجرة التً تحوي الحرف ''h فإذا فرضنا أنّ "ُ "helloخ ّزنت فً العنوان 2813وما بعده فإنّ الذي ت ّم ٌُلخصه الشكل التالً:
مصفوفة المؤ ّ شرات ٌمكن أن نع ّرف مصفوفة مإ ّ شرات كما ٌلً : ;]type* name[ELEMENTS مثال :
مصفوفة 4مإ ّ شرات على سبلسل //
;]char* cars[3
;"char[0]="Mercedes ;"char[1]="Nissan ;"char[2]="Ferrari
:9
العمل ٌّات الحسابٌة على المؤ ّ شرات العملٌّات الحسابٌة على المإ ّ شرات تختلف قلٌبلعن تلك التً ننفذها على األعداد الصحٌحة إذ ٌمكن أن ننفذ فقط عملٌتً الجمع والطرح أمّا الضرب والقسمة فلٌس لهما أي معنى فى عالم المإ ّ شرات .لكن الجمع والطرح لهما شرات وذلك بحسب حجم نوع المعطٌات التً تشٌر إلٌها المإ ّ سلوك مختلف مع المإ ّ شرات. كما نعلم فإنّ مقدار ما ٌت ّم حجزه من الذاكرة ٌعتمد على نوع المعطٌات فمثبل النوع )ٌ (charحجز 2باٌت والنوع )ٌ (shortحجز 3باٌت أما النوع ) (longفٌحجز 5باٌت ولنفرض أ ّنه لدٌنا ثبلثة مإ ّ شرات ;char *mychar ;short *myshort ;long *mylong وبفرض أ ّنها تشٌر إلى حجرات الذاكرة 4111 , 3111 , 2111بالترتٌب فإذا كتبنا ;mychar++ ;myshort++ ;mylong++ عندب ٍذ المإ ّ شر mycharسٌحوي القٌمة 2112و myshortسٌحوي القٌمة 2113و mylongسٌحوي ّ القٌمة 2115وسبب ذلك أننا عندما نضٌف 2إلى المإشر معنى ذلك أننا نجعله ٌشٌر إلى العنصر التالً لنفس النوع الذي عرفناه أي ٌضاف الحجم بالباٌت إلى المإ ّ شر حسب النوع. حجم النوع ) 2 (charباٌت لذلك تم إضافة 2إلى المإ ّ شر mychar حجم النوع ) 2 (shortباٌت لذلك تم إضافة 2إلى المإ ّ شر myshort حجم النوع ) 4 (longباٌت لذلك تم إضافة 4إلى المإ ّ شر mylong
سٌحدث نفس األمر تماما إذا كتبنا ;mychar = mychar + 1 ;myshort = myshort + 1 ;mylong = mylong + 1
::
من المهم التنبٌه إلى أنّ معامبل الزٌادة ) (++والنقصان ) (--لهما أولوٌّة على معامل المرجع )*( لذلك فإنّ التعابٌر التالٌة ربما تسبب التباس فً فهمها ;*p++ ;*p++ = *q++ التعبٌر األول مكافا لـ ) *(p++وهو ٌقوم بزٌادة 2إلى العنوان الذي ٌحوٌه المإ ّ شر pولٌس القٌمة التً ٌشٌر إلٌها وبالتالً فإنّ القٌمة الجدٌدة التً ٌشٌر إلٌها pهً قٌمة عشوابٌة. فً التعبٌر الثانً بما أنّ المعاملٌن ) (++و ) (--بعد المساواة التً ٌجب أن تتح ّقق فإنّ القٌمة ُ *qتسند إلى *p ث ّم ٌُزاد ك ّل من pو qبمقدار 2أي التعبٌر الثانً مكافا لـ ;*p = *q ;p++ ;q++ لذلك ٌنبغً استخدام األقواس لتجنب األخطاء.
شرات على المؤ ّ المؤ ّ شرات
شرات تشٌر إلى مإ ّ ٌمكن فً لغة C++استخدام مإ ّ شرات أخرى والتً تشٌر بدورها إلى بٌانات .لفعل ذلك نحتاج فقط إلى أن نضٌف * إلى ك ّل مستوى من التؤشٌر فمثبل: ;char a ;char * b ;char ** c ;'a = 'z ;b = &a ;c = &b
بفرض حجرات الذاكرة التً حُجزت عشوابٌا مبٌّنة بالشكل:
الجدٌد فً هذا المثال هو المتغٌّر cالذي ٌمكن أن ٌد ّل على ثبلث قٌم مختلفة هو متغٌّر من النوع )** (charوقٌمته 8092 c *cهو متغٌّر من النوع )* (charوقٌمته 7230 **cهو متغٌّر من النوع ) (charوقٌمته ''z مالحظة
المؤ ّ شرات الخالٌة ()void pointers
*c == b == 7230 '**c == *b == a == 'z
المإ ّ شر ذو النوع ٌ voidمكنه أن ٌشٌر إلى أي نوع من المعطٌات سواء كان صحٌحا ) (integerأو حقٌقٌا ) (floatأو سلسلة رموز) .(string of charactersفً هذا النوع من المإ ّ شرات ال نستطٌع أن نستخدم معامل المرجع * بشكل مباشر ألنّ طول المإ ّ شر غٌر معلوم ,ولهذا السبب ٌجب علٌنا أن نلجؤ دابما إلى تحوٌل النوع voidإلى نوع آخر مح َّدد من المعطٌات.
211
ّ من فوابد هذا المإ : ًشر هو إمكانٌة تمرٌر قٌم عامّة إلى تابع ما كما فً المثال التال // integer increaser #include <iostream> using namespace std;
6, 10, 13
void increase (void* data, int type) { switch (type) { case sizeof(char) : (*((char*)data))++; break; case sizeof(short): (*((short*)data))++; break; case sizeof(long) : (*((long*)data))++; break; } } int main () { char a = 5; short b = 9; long c = 12; increase (&a,sizeof(a)); increase (&b,sizeof(b)); increase (&c,sizeof(c)); cout << (int) a << ", " << b << ", " << c; return 0; }
هوsizeof(char) فمثبل, هو تابع مدمج فً اللغة ٌرجع قٌمة ثابتة تمثل الحجم بالباٌت لما بٌن القوسٌنsizeof . باٌت2 هوchar ألنّ طول النوع2
ّ المؤ شرات على التوابع
ّ نصرّ ح عن المإ.شرات على التوابع ٌمكن أن نم ّرر التابع كمعامل لتابع آخر ّ من خبلل المإ شر على تابع بنفس .* األسلوب الذي نصرّ ح به عن تابع باستثناء أ ّننا نضع االسم بٌن قوسٌن ونسبقه بـ :مثال // pointer to functions #include <iostream> using namespace std; int addition(int a, int b) { return (a+b); } int subtraction(int a, int b) { return (a-b); } int (*minus)(int,int) = subtraction;//pointer to function int operation(int x, int y, int (*p)(int,int)) { int g; g = (*p)(x,y); return (g); }
212
8
int main () { int m,n; m = operation(7, 5, addition); n = operation(20, m, minus); cout <<n; return 0; }
ّ هو مإminus subtraction أسندنا التابع.int ٌقبل معاملٌن من النوعint شر عام على تابع من النوع ّ إلى المإ فً سطر التعرٌف نفسهminus شر int (* minus)(int,int) = subtraction;
213
الفصل الثاني شصر:
ح ّتى اآلن كان حجز الذاكرة فً برامجنا ٌت ّم أثناء كتابة الكود أي أثناء التصرٌح عن المتغٌّرات المختلفة قبل تنفٌذ البرنامج .ولكن ماذا لو احتجنا مقداراا متغ ٌّراا من الذاكرة ٌت ّم تحدٌده أثناء تنفٌذ البرنامج؟ مثبل فً حال احتجنا إلى دخل من المستخدم لنحدّد الحجم البلزم حجزه. اإلجابة على ذلك هً الذاكرة الدٌنامٌكٌة التً من أجلها تحوي C++معاملً newو delete
المعامل new لكً نطلب ذاكرة دٌنامٌكٌة نستخدم المعامل newمتبوعا بنوع المعطٌات أو متبوعا بنوع المعطٌات و قوسٌن مربعٌن ] [ ٌحوٌان عدد العناصر المطلوبة. ٌ عٌد المعامل newمإ ّ شرا ٌشٌر إلى أول حجرة من حجرات الذاكرة التً ت ّم حجزها. نستخدمه كما ٌلً ;pointer = new type لحجز ذاكرة تحوي عنصر واحد من نوع المعطٌات. أو لحجز ذاكرة تحوي مجموعة عناصر)مصفوفة( من نوع المعطٌات ;]pointer = new type[elements مثال: ;int * p ;]p = new int [5 فً هذه الحالة ٌقوم النظام بحجز مقدار من الذاكرة مإلّف من 6حجرات من النوع intوٌعٌد مإ ّ شرا ٌشٌر إلى أول حجرة من الحجرات الخمس وت ّم إسناد قٌمة هذا المإ ّشر إلى المإ ّ شر . p إذا ٌ pشٌر إلى أول خانة من 6خانات من النوع intكما فً الشكل
سابقا عند التصرٌح عن المصفوفة كان ٌجب أن ٌكون عدد العناصر قٌمة ثابتة أمّا فً الذاكرة الدٌنامٌكٌة فٌمكن أن ٌكون عدد العناصر متغٌّرا ٌقوم المستخدم بإدخاله العدٌد من البرامج تستخدم الذاكرة الدٌنامٌكٌة و ٌت ّم أحٌانا استهبلك الذاكرة بشكل كامل لذلك ٌجب التؤكد من أنّ الحجز قد ت ّم بشكل صحٌح عند استخدام newكما ٌلً ;int * p ;]p = new int [5 )if (p == NULL exit(1); // error assigning memory.
214
المعامل delete بعد أن تنتهً حاجتنا إلى الذاكرة التً حجزناها باستخدام ٌ newنبغً علٌنا أن نحرّ رها باستخدام المعامل deleteلكً تصبح متاحة للحجز الحقا ,ونستخدمه كما ٌلً: لتحرٌر الذاكرة المحجوزة لعنصر واحد أو لتحرٌر الذاكرة المحجوزة لعدة عناصر )مصفوفة(.
;delete pointer ;delete [] pointer
مثال: enter the number of courses: 7 mark 1= 91 mark 2= 78 mark 3= 77 mark 4= 68 mark 5= 83 mark 6= 73 mark 7= 81 average= 78.7143
//calculate average using dynamic memory >#include <iostream >#include<stdlib.h ;using namespace std
)( int main { ;int n,i,sum=0 ;" cout<<"enter the number of courses: ;cin>>n ;]int *p=new int[n ;)if(p==NULL)exit(1 )for(i=0;i<n;i++ { ;" ="<<cout<<"mark "<<i+1 )cin>>p[i];//or cin>>*(p+i ;]sum+=p[i } ;cout<<"average= "<<(float)sum/n<<endl ;delete [] p ;return 0 }
NULLهً قٌمة ثابتة مع ّرفة فً مكتبات C++لتد ّل على المإ ّ شرات الفارغة )التً ال تشٌر إلى شًء(. #define NULL 0 فً حال لم تكن معرّ فة فٌمكن أن تع ّرفها بنفسك كما ٌلً: ال ٌوجد فارق أن تضع 1أو NULLعندما تفحص المإ ّ شرات ,ولكن NULLمستخدمة بشكل أكبر وهً أكثر وضوحا أل ّننا نادرا ما نقارن المإ ّ شرات مع قٌم ثابتة أو نسندها إلى أرقام.
215
الفصل الثالث شصر:
تراكٌب المعطٌات تركٌب المعطٌات هو نوع ٌقوم المستخدم بتعرٌفه وٌتؤلف من أنواع مختلفة من البٌانات ذات الحجوم المختلفة مجموعة فً تصرٌح واحد بالشكل : { struct name ;data_type element1 ;data_type element2 . . ;data_type elementN ; } object1_name, object2_name, … , objectN_name :nameاسم التركٌب. :object_nameاسم الكابن الذي نرٌد أن نشتقه من التركٌب )تعرٌفه هنا اختٌاري(. أنواع البٌانات المختلفة التً ٌحوٌها التركٌب موجودة بٌن القوسٌن { }. مثال: { struct products ;]char name [30 ;float price ;} apple, orange, melon
عرّ فنا أوال التركٌب productsالذي ٌتؤلف من حقلٌن هما nameو priceك ّل منهما له نوع مختلف عن نوع اآلخر. بعد أن عرّ فنا التركٌب قمنا بتعرٌف ثبلثة كابنات من نفس النوع productsوهً apple :و orangeو .melon ٌمكن أن نشتق الكابنات من التركٌب بطرٌقة أخرى وذلك بؤن نعرف الكابن المشتق باستخدام اسم التركٌب .مثبل: { struct products ;]char name [30 ;float price ;} ;products apple ;products orange, melon 216
كل منهما له نوع مختلف عن نوعprice وname الذي ٌتؤلف من حقلٌن هماproducts عرّ فنا أوال التركٌب .اآلخر :ً( للتصرٌح عن ثبلثة كابنات من النوع نفسه هproducts) بعد أن عرّ فنا التركٌب استخدمنا اسم التركٌب .melon وorange وapple ٌصبح اسم نوع جدٌد مثل األنواع األساسٌةproducts ّ( فإنproducts) بعد أن صرّ حنا عن التركٌب ( وٌصبح بإمكاننا أن نصرح عن كابنات )متغٌّراتshort أوchar أوint المعرفة مسبقا كالنوع .من هذا النوع وname ٌصبح لكل منها حقبلن هماmelon وorange وapple بعد أن صرحنا عن الكابنات .( ث ّم اسم الحقل.) ٌمكن أن نتعامل مع الحقول بذكر اسم الكابن تلٌه نقطةprice أمثلة apple.name orange.name char [30] melon.name apple.price orange.price float melon.pric
مثال // example about structures #include <iostream> using namespace std; #include <string> struct students{ char name[50]; char city[50]; int tel; }st1,st2; int main() { //filling information cout<<"enter student1 name, city and tel_no: "; cin>>st1.name; cin>>st1.city; cin>>st1.tel; cout<<"enter student2 name, city and tel_no: "; cin>>st2.name; cin>>st2.city; cin>>st2.tel; //printing information cout<<"\nname"<<"\tcity\t"<<"tel_no"; cout<<"\n------------------------\n"; cout<<st1.name<<"\t"<<st1.city<<"\t"<<st1.tel<<endl; cout<<st2.name<<"\t"<<st2.city<<"\t"<<st2.tel<<endl; return 0; }
217
enter student1 name, city and tel_no: Ali Hama 3245675 enter student2 name, city and tel_no: Ahmad Homs 2452658 name city tel_no ---------------------------Ali Hama 3245675 Ahmad Homs 2452658
مصفوفة التراكٌب التراكٌب مٌزة كثٌرا ما تستخدم لبناء قواعد المعطٌات خاصة إذا استخدمناها مع المصفوفات حٌث ٌمكن بناء : ًمصفوفة تراكٌب باإلعبلن عن التركٌب أوال ث ّم نعلن عن مصفوفة من نوع التركٌب كما ٌل struct name { type element1; type element2; . . type elementN; } object_name [ELEMENTS]; :مثال // array of structures #include <iostream> using namespace std; #include <stdlib.h> #define N_BOOKS 5 struct book { char title [50]; int year; } books [N_BOOKS]; void printBook (book mybook); int main () { char buffer [50]; int n; cout<<"please enter the titles and years for 5 books!.\n"; for (n=0; n< N_BOOKS; n++) { cout << "title: "; cin.getline (books[n].title,50); cout << "year: "; cin.getline (buffer,50); books[n].year = atoi(buffer); }
218
Enter Enter Enter Enter Enter Enter Enter Enter Enter Enter
title: java how to program year: 1997 title: eat, pray, love year: 2006 title: advanced memory year: 2005 title: being logical year: 2004 title: c++ how to program year: 2005
You have entered these movies: java how to program (1997) eat, pray, love (2006) advanced memory (2005) being logical (2004) c++ how to program (2005)
cout << "\nYou have entered these books:\n"; for (n=0; n< N_BOOKS; n++) printBook (books[n]); return 0; } void printBook (book mybook) { cout << mybook.title; cout << " (" << mybook.year<< ")\n"; }
ّ التراكٌب و المؤ شرات
ّ ٌمكن استخدام للمإ : ًشرات لتشٌر إلى التراكٌب كما ٌل struct book { char title [50]; int year; }; book abook; book * pbook; book هو كابن من النوع:abook ّ هو مإ:pbook book شر ٌشٌر إلى كابن من النوع ّ ولجعل المإ نكتبabook ٌشٌر إلى الكابنpbook شر pbook = &abook; مثال // pointers to structures #include <iostream> using namespace std; #include <stdlib.h> struct book { char title [50]; int year; } ; int main () { char buffer[50]; book abook; book * pbook; pbook = &abook; cout<<"please enter a book title and its publish year!.\n"; cout << "title: "; cin.getline (pbook->title,50); cout << "Enter year: "; cin.getline (buffer,50); pbook->year = atoi (buffer); cout << "\nYou have entered:\n"; cout << pbook->title; cout << " (" << pbook->year << ")\n"; return 0; }
219
Enter title: c++ how to program Enter year: 2005 You have entered: c++ how to program (2005)
شرات على التراكٌب أو المإ ّ المعامل )> (-هو معامل مرجعً ٌستخدم خصٌصا مع المإ ّ شرات على األصناف للوصول إلى الحقول الموجودة فٌها وهو ٌلغً الحاجة الستخدام األقواس فً كل مرة نرٌد أن نصل إلى حقل ما فً تركٌب ما. pbook->title
(*pbook).title
كبل العبارتٌن صحٌحتان وتعنٌان أ ّننا نتعامل مع الحقل titleالمشار إلٌه بالمإ ّ شر pbook وٌجب أن نمٌزهما عن العبارتٌن : *pbook.title
)*(pbook.title
اللتٌن تعنٌان أ ّننا نتعامل مع القٌمة المشار إلٌها بالعنصر ) titleالذي ال ٌعتبر مإ ّ شرا باألساس( أي أنّ العبارتٌن األخٌرتان خاطبتان وال تعنٌان شٌبا. ٌلخص الحاالت الممكنة للمإ ّ الجدول التالً ّ شرات والتراكٌب العببرة
الوصف
pbook.title
العنصر titleمن التركٌب pbook
pbook->title
العنصر titleمن التركٌب المشار إلٌه بالمإ ّ شر pbook القٌمة المشار إلٌها بالعنصر titleمن التركٌب pbook
*pbook.title
العببرة المكبفئت
(*pbook).title )*(pbook.title
التراكٌب المتداخلة تراكٌب أخرى كما فً المثال التالً: ٌمكن أن تكون التراكٌب حقوال موجودة داخل َ {struct books ;]char title [50 ;int year } {struct friends ;]char name [50 ;]char email [50 ;books favourite_book ;} ahmad,ali ;friends *p = &ahmad بعد هذه التصرٌحات ٌمكن أن نستخدم العبارات التالٌة : ahmad.name ali.favourite_book.title ahmad.favourite_book.year p->favourite_book.year
21:
: اكتب برنامج ٌقوم باستعراض البحة تتضمن . إدخال اسم جدٌد لطالب.2 . استعراض كل أسماء الطبلب المدخلة.3 . البحث عن طرٌق إدخال اسم الطالب.4 . البحث عن طرٌق إدخال السنة الدراسٌة للطالب.5 . ترتٌب أسماء الطبلب أبجدٌا.6 . الخروج من البرنامج.7
#include<iostream> #include<string> using namespace std; #define M 100 int count=0; struct studentsType { string name; int age,year; }student[M]; void add(); void browse(); void searchByName(); void searchByYear(); void order(); int main() { int choice; do { cout<<"please enter your choice!.\n"; cout<<"1-add new student\n2-browse\n3-search by name\n4-search by year" <<"\n5-alphabetical order\n6-exit\n"; cin>>choice; switch(choice) { case 1: add();break; case 2: browse();break; case 3: searchByName();break; case 4: searchByYear();break; case 5:order();break; case 6: return 0; } }while(count<M); return 0; } 221
void add() { cout<<"student name: ";cin>>student[count].name; cout<<"student age: ";cin>>student[count].age; cout<<"student Year: ";cin>>student[count].year; count++; cout<<"\n"; } void browse() { cout<<"name\tage\tyaer\n"; for(int i=0;i<count;i++) cout<<student[i].name<<"\t"<<student[i].age<<"\t"<<student[i].year<<"\n"; cout<<"\n"; } void searchByName() { string name; bool found=false; int i; cout<<"enter name:";cin>>name; for(i=0;i<count;i++) { if(name==student[i].name) { cout<<student[i].name<<"\t"<<student[i].age<<"\t"<<student[i].year<<"\n"; found=true; } } if(!found) cout<<name<<" was not found\n"; cout<<"\n";
} void searchByYear() { int y; bool found=false; int i; cout<<"enter year:";cin>>y; for(i=0;i<count;i++) { if(student[i].year==y) {
222
cout<<student[i].name<<"\t"<<student[i].age<<"\t"<<student[i].year<<"\n"; found=true; } } cout<<"\n"; if(!found) cout<<"no result\n"; } void order() { int i,j; studentsType temp; if(count<2)goto out; for(i=0;i<count;i++) { for(j=0;j<count-1;j++) { if(student[j].name>student[j+1].name) { temp=student[j]; student[j]=student[j+1]; student[j+1]=temp; } } } cout<<"\n"; out:browse(); }
223
الفصل الرابع شصر:
نوع بٌانا ٍ ت ٌع ّرفه المستخدم )المبرمج ( ,باإلضافة إلى التراكٌب توجد تعرّ فنا سابقا على التراكٌب التً تعتبر َ أنوع أخرى مثل:
صة ()typedef تعرٌف أنواع خا ّ ٌمكن أن نعرف أنواع خاصّة بنا باالعتماد على أنواع معرّ فة وموجودة مسبقا باستخدام الكلمة المفتاحٌة typedefالتً ُتستخدم كما ٌلً : ;new_type_name
existing_type
Typedef
:existing_typeهو النوع األصلً المعرف فً C++أو أي نوع مع ّرف مسبقا. :new_type_nameهو اسم النوع الجدٌد الذي سنعرفه .مثبل : ;char C ;unsigned int WORD ;char * string_t ;]char field [50
typedef typedef typedef typedef
هنا عرّ فنا أربعة أنواع جدٌدة هً Cو WORDو string_tو fieldعلى أنها charو unsigned intو * charو ] char[50بالترتٌب ,وبالتالً ٌمكن استخدام هذه األنواع لتعرٌف متغٌّرات كما ٌلً : ;C achar, anotherchar, *ptchar1 ;WORD myword ;string_t ptchar2 ;field name typedefمفٌدة لتعرٌف نوع س ٌُستخدم بكثرة فً البرنامج ومن الممكن أن تحتاج لتغٌٌرهذا النوع فٌما بعد, كما تستخدم أحٌانا عندما ٌكون اسم النوع طوٌبل وترٌده أن ٌكون مختصرا.
الوحدات )(Unions الـ unionهو تركٌب جمٌع عناصره ٌت ّم حجزها فً نفس العنوان الذاكري. طرٌقة اإلعبلن عنها واستخدامها مشابهة للطرٌقة المتبعة فً التراكٌب لكنّ عملها مختلف تماما: { union model_name ;type1 element1 ;type2 element2 ;type3 element3 . . ;} object_name الحجم الـذي ٌشغله الـ unionهو حجم أكبر عنصر فٌه. 224
مثبل: { union mytypes_t ;char c ;int i ;float f ;} mytypes تنتج العناصر : mytypes.c mytypes.i mytypes.f كل واحد من هذه العناصر له نوع مختلف ولكنها فً نفس الموقع من الذاكرة وأي تعدٌل على قٌمة أحد العناصر سٌإثر على قٌم كل العناصر.
المر ّقمات )Enumerations(enum ٌسمح هذا النوع بتعرٌف أنواع بٌانات ٌمكن أن تؤخذ قٌم مختلفة محدّدة من قبل المستخدم والشكل العام لها هو : { enum model_name value1, value2, value3, . . ;} object_name مثال:
;}enum colors {black, blue, green, cyan, red, purple, yellow, white الحظ أ ّننا لم نضمّن أي نوع بٌانات أساسً أي أ ّننا أنشؤنا نوع بٌانات جدٌد دون اإلعتماد على نوع موجود مسبقا وهو النوع colorsالذي ٌؤخذ أحد القٌم الموجودة بٌن القوسٌن }{ وعندما نعرّ ف الكابن mycolor من هذا النوع فإنّ العبارات التالٌة صحٌحة: ;colors mycolor ;mycolor = blue ;if (mycolor == green) mycolor = red فً الواقع إنّ البٌانات الموجودة داخل القوسٌن }{ تستبدل بقٌم عددٌة صحٌحة أثناء الترجمة والقٌم االفتراضٌة هً 2ألول عنصر و 1للثانً و 3للثالث وهكذا... أمّا إذا خصّصنا قٌمة ألول عنصر فإنّ قٌمة العنصر الثانً تزٌد عن قٌمة األول بواحد وهكذا.. مثبل إذا كتبنا black=1بدال من blackوتركنا العناصر الباقٌة كما هً فإنّ whiteسٌؤخذ القٌمة .8
225
الفصل اخلامس شصر:
الملفات تش ّكل أساس التعامل مع الحاسب فعندما تعمل على أي حاسب الب ّد لك من أن تفتح مل ّفا ما أو تكتب على ملف سواء كان هذا الملف نصّا أو صورة أو صوتا. ..إلخ. ّ تخزن فً الذاكرة العشوابٌة وٌت ّم فقدانها عند إنهاء فً معظم البرامج التً كتبناها سابقا كانت المعلومات البرنامج فإذا ك ّنا بحاجة لهذه المعلومات فٌمكننا تخزٌنها فً ملفات على القرص الصلب الستعادتها الحقا. تدعم لغة C++اإلدخال واإلخراج فً الملفات من خبلل الصفوف التالٌة :
:ofstreamصف الملفات الخاص بعملٌات الكتابة )مشتق من الصف ( ostream :ifstreamصف الملفات الخاص بعملٌات القراءة )مشتق من الصف ( istream :fstreamصف الملفات الخاص بعملٌات القراءة والكتابة )مشتق من الصف (iostream
فتح ملف
عموما العملٌة األولى التً تن ّفذ على كابن من الصفوف المذكورة هً ربط هذا الكابن بملف حقٌقً أي عملٌة فتح ملف ,هذه العملٌة ُت ّ مثل فً البرنامج من خبلل الكابن ) (streamوأي دخل أو خرج ٌنفذ على هذا الكابن سٌطبق على الملف الحقٌقً.
لكً نفتح ملفا عن طرٌق الكابن streamنستخدم تابعه العضوي )( openالمعرّ ف بالشكل : ;)mode
void open (const char * filename, openmode
:filenameسلسلة رموز تمثل اسم الملف المراد فتحه. :modeوضعٌة الفتح وهً مزٌج من األوضاع المبٌنة بالجدول : ios::in ios::out ios::ate ios::app ios::trunc ios::binary
فتح الملف للقراءة فتح الملف للكتابة الوضع االبتدابً :نهاٌة الملف كل خرج ٌضاف إلى نهاٌة الملف إذا كان الملف موجود سابقا فٌت ّم حذفه الوضع الثنابً
ٌمكن الجمع بٌن هذه األوضاع بالمعامل "أو" الثنابً | .مثبل إذا أردنا فتح الملف " "example.binفً الوضع الثنابً إلضافة بٌانات ٌمكن أن نفعل ذلك باستدعاء التابع العضوي openكالتالً: ;ofstream file ;)file.open ("example.bin", ios::out | ios::app | ios::binary لكل تابع openمن التوابع الخاصة بالصفوف ofstreamو ifstreamو fstreamوضع افتراضً خاص ٌختلف من صف إلى آخر كما فً الجدول : الصف ofstream ifstream fstream
الوضع االفتراضً للفتح ios::out | ios::trunc ios::in ios::in | ios::out
226
تطبق القٌمة االفتراضٌة فقط فً حال ت ّم استدعاء التابع بدون تخصٌص البارامتر .mode
بما أنّ العملٌة األولى التً تنفذ على الكابن من الصفوف السابقة هً عملٌة فتح ملف فإنّ كبل من هذه الصفوف الثبلثة ٌحتوي على مشٌد )بانً( ٌقوم باستدعاء التابع openبنفس البارامترات ,لذلك ٌمكننا أن نعرّ ف الكابن ونستدعً التابع بسطر واحد كما ٌلً: ;)ofstream file ("example.bin", ios::out | ios::app | ios::binary
ٌمكنك التحقق من أنّ الملف قد فُتح بشكل صحٌح باستدعاء التابع العضوي )(is_open هذا التابع ٌُعٌد trueإذا ت ّم ربط الكابن بالملف بشكل صحٌح ّ وإال فإ ّنه ٌُعٌد .false
;)(bool is_open
إغالق ملف عندما تنتهً عملٌات القراءة أو الكتابة أو فً حال اكتمال الملف فٌجب إغبلقه لٌصبح متاحا لبلستخدام ثانٌة. لفعل ذلك نستدعً التابع العضوي )( closeالمعرّ ف كما ٌلً: ;)( void close بعد استدعاء هذا التابع ٌصبح الكابن streamجاهزا لفتح ملف آخر فً حالة هدم الكابن وهو ماٌزال مرتبط بالملف فإنّ الهادم ٌستدعً التابع closeتلقابٌا.
صٌة الملفات الن ّ الصفوف ofstreamو ifstreamو fstreamمشتقة من الصفوف ostreamو istreamو iostreamلذلك فإنّ كابنات الـ ٌ fstreamمكنها أن تستخدم عناصر الصفوف األصلٌة لتصل إلى المعطٌات ,أي ٌمكننا أن نستخدم cinو coutمع الكابنات التً نعرّ فها كما فً المثال التالً حٌث نستخدم معامل اإلدخال << الذي ت ّم إعادة تحمٌله file example.txt This is a line. This is another line.
// writing on a text file >#include <iostream >#include <fstream ;using namespace std { )( int main ;)"ofstream examplefile ("example.txt ))(if (examplefile.is_open { ;"examplefile << "This is a line.\n ;"cout<< "This is a line.\n ;"examplefile << "This is another line.\n ;"cout<< "This is another line.\n ;)(examplefile.close } ;"else cout<<"Unable to open the file ;return 0 }
227
كما أنّ إدخال البٌانات من ملف ٌنفذ بنفس الطرٌقة التً نستخدم بها :cin // reading a text file >#include <iostream >#include <fstream >#include <stdlib.h ;using namespace std
This is a line. This is another line.
{ )( int main ;]char buffer[256 ;)"ifstream examplefile ("example.txt ))(if (! examplefile.is_open } ;){ cout << "Error opening file"; exit (1 ) )(while (! examplefile.eof { ;)examplefile.getline (buffer,100 ;cout << buffer << endl } ;return 0 }
هذا البرنامج ٌقوم بقراءة ملف نصًّ وٌطبع محتواه على الشاشة. التابع العضوي )(ٌ eofعٌد trueعند الوصول إلى نهاٌة الملف.
التحقق من الحالة باإلضافة إلى التابع )( eofتوجد توابع عضوٌة أخرى للتحقق من حالة الكابن )الملف( تعٌد كلها قٌم منطقٌة )(bool )(:bad ٌعٌد trueإذا حدث خطؤ فً عملٌة القراءة أو الكتابة .مثبل إذا حاولنا الكتابة على ملف غٌر مفتوح ألجل الكتابة. )(:fail ٌعٌد trueكما فً حالة التابع )( badكما ٌعٌد trueفً حال حدوث خطؤ فً صٌغة الملف كما فً حالة قراءة عدد صحٌح وت ّم إدخال حرف. )(:good ٌعٌد falseفً نفس الحاالت التً تعٌد فٌها التوابع السابقة .true لتصفٌر عبلمات الحالة التً ت ّم فحصها بالتوابع السابقة نستخدم التابع )( clearبدون وسطاء.
مؤ ّ شرا التدفق ( getو )put جمٌع كابنات التدفق الخاصة بالدخل والخرج تحوي مإ ّ شرا واحدا على األقل:
ifstreamمثل ٌ istreamحوي المإ ّ شر getالذي ٌشٌر إلى العنصر التالً المراد قراءته. ّ ofstreamمثل ٌ ostreamحوي المإشر putالذي ٌشٌر إلى المكان الذي سٌكتب فٌه العنصر التالً. وأخٌرا fstreamمثل ٌ iostreamرث ّ كبل من getو .put
228
ٌمكن التعامل مع هذه المإ ّ شرات من خبلل التوابع التالٌة: )( tellgو )(tellp هذان التابعان ال ٌقببلن وسطاء وٌعٌدان قٌمة من النوع pos_typeوهً قٌمة من النوع الصحٌح )(integer شر ) getفً حالة التابع )( ( tellgأو مكان المإ ّ تمثل المكان الحالً للمإ ّ شر ) putفً حالة التابع )(.(tellp )( seekgو )(seekp ّ ٌقوم هذان التابعان بتغٌٌر مكانً المإشرٌن getو putوت ّم إعادة تحمٌلهما كما ٌلً : ;) seekg ( pos_type position ;) seekp ( pos_type position باستخدام هذا الشكل ٌت ّم تحوٌل المإ ّ شر إلى مكان ٌبعد بعدا ثابتا عن بداٌة الملف والوسٌط المطلوب من نفس النوع الذي ٌعٌدانه التابعان )( tellgو )(.tellp ;) seekg ( off_type offset, seekdir direction ;) seekp ( off_type offset, seekdir direction باستخدام هذا الشكل ٌت ّم تحوٌل المإ ّ شر إلى مكان ٌبعد بعدا ثابتا عن نقطة معٌنة بحٌث: :off_typeنوع مكافا للنوع .long :directionالوجهة التً سٌتم نقل المإ ّ شر إلٌها وٌجب أن تؤخذ إحدى الحاالت التالٌة: ios::begإلى بداٌة الملف ios::curمن المكان الحالً للمإ ّ شر ios::endإلى نهاٌة الملف المثال التالً ٌستخدم التوابع المذكورة لحساب حجم ملف ثنابً: size of example.txt is 40 bytes.
// obtaining file size >#include <iostream >#include <fstream ;using namespace std ;"const char * filename = "example.txt { )( int main ;long l,m ifstream file (filename, ;)ios::in|ios::binary ;)(l = file.tellg ;)file.seekg (0, ios::end ;)(m = file.tellg ;)(file.close ;cout << "size of " << filename ;"cout << " is " << (m-l) << " bytes.\n ;return 0 }
229
الفصل السادس شصر:
مالحظة :معالجة االستثناءات من المٌزات الحدٌثة التً ت ّم إنتاجها مع لغة ANSI-C++القٌاسٌة. لذلك إذا كنت تستعمل مترجما ا ال ٌدعم هذه اللغة القٌاس ٌّة فمن الممكن ّأال تكون قادراا على استخدامها.
أثناء تطوٌر البرنامج قد نتعرض لمواقف ال نستطٌع فٌها أن نح ّدد فٌما إذا كانت هذه الشٌفرة ستعمل بالشكل الصحٌح أو ال وذلك أل ّنه قد تكون هناك بعض الحاالت التً ال نتو ّقع حدوثها والتً قد تتسبب بخطؤ فً البرنامج .مثل هذه المواقف هو ما ندعوه باالستثناءات. وأخٌرا قدمت C++ثبلث معامبلت جدٌدة ) (try, throw, catchلتساعدنا فً معالجة هذه الحاالت وهً تؤخذ الشكل التالً: { try اٌش١فشح اٌز ٟعزؼًّ أ ّٚلً // ٠شعً ِزغّ١شاً ٠غزخذَ ٌّؼشفخ العزضٕبء اٌؾبطًthrow exception; // } )catch (type exception { اٌش١فشح اٌز ٟع١زُ رٕف١ز٘ب ؽ٠ ٓ١ؾذس العزضٕبء // } وهً تعمل بالطرٌقة التالٌة: الشٌفرة داخل التعلٌمة ُ tryتن َّفذ بشكل طبٌعً ,وبمجرّ د حصول استثناء ما ٌت ّم استدعاء التعلٌمة throw التً تعٌد وسٌطا قٌمته وصفٌ لبلستثناء الحاصل و ٌؤخذ )الوسٌط( أي نوع مناسب لبلستثناء. إذا حصل االستثناء فإنّ التعلٌمة catchستعمل على استقبال الوسٌط الممرّ ر من التعلٌمة throwو ّإال فإنّ التعلٌمة catchلن تن ّفذ.
مثال :
Exception: Out of range
// exceptions >#include <iostream ;using namespace std { )( int main ;]char myarray[10 try { )for (int n=0; n<=10; n++ ;"{ if (n>9) throw "Out of range ;'myarray[9]='z } } )catch (char * str } ;{ cout << "Exception: " << str << endl ;return 0 }
22:
عندها فإنّ التعلٌمة التً ستن ّفذ هً تلك. لٌقبل أكثر من نوع من الوسطاءcatch ٌمكننا أن نعٌد تحمٌل المعامل .throw التً تقابل الحالة الحاصلة وٌتعرّ ف المترجم علٌها من خبلل الوسٌط المرسل من التعٌمة : مثال // exceptions: multiple catch blocks #include <iostream> using namespace std; int main () { try { char * mystring; mystring = new char [10]; if (mystring == NULL) throw "Allocation failure"; for (int n=0; n<=100; n++) { if (n>9) throw n; mystring[n]='z'; } } catch (int i) { cout << "Exception: "; cout << "index " << i << " is out of range" << endl; } catch (char * str) { cout << "Exception: " << str; } return 0; }
Exception: index 10 is out of range
: فً هذا المثال ٌوجد احتماالن لحدوث استثنابٌن مختلفٌن عندها سٌت ّمmystring األول هو أ ّال ٌت ّم إسناد أيّ حرف من الحروف العشر المشكلة للمصفوفة ّ .catch( char * str ){…} استدعاء التعلٌمة .catch ( int i ) {…} عندها ُتستدعى التعلٌمة9 القٌمة أكبر منi الثانً عندما ٌؤخذ العدّاد
231
-
القسم الثالث إذا غامرت يف َشر ٍ ف َم ُر ِوم َْ َ َ فطَ ْع ُِ امل ْو ِت يف ْأم ٍر َح ِق ٍي َ جز َع ْق ٌل الع ن أ ناء َيرى اجلُبَ ُ ّ َ َ جاع ٍة يف امل ْرِء تُغين كل َش َ و ّ َ وكِ من عائِ ٍ صحيحاً ب ْقولً َ ْ ِ وِ لك ْن ُ تأخ ُذ اآلذا ُن مْنهُ
فَال تَقنَ ْع مبا دو َن كطَ ْع ِ امل ْو ِت يف ْأم ٍر َ ديعةُ الطّب ِع خ وتهِ ه ه ه ه ه ه َ مك َ َ ِ جاع ِة يف ثل ّ الش َ ول م َ وآفَهتُهُ ِم َن ال َف ُْ ِِ عمى قَ َد ِر ال َقَرائِ ِح
الن ِ جوم ّ َعظي ِ المّئي ِ احلَكي ِ السقي ِ ّ والعُُز ِوم المتنبّي
232
الفصل السابع شصر:
مق ّدمة: ح ّتى هذه اللحظة ك ّل البرامج التً كتبناها كانت من نمط البرمجة الهٌكل ٌّة أي أنّ البرنامج له مسار مح ّدد ال ٌمكن أن ٌتغ ٌّر ,وٌواجه المبرمجون مشاكل عدٌدة فً هذا النمط من البرمجة حٌث تصبح عمل ٌّة تت ُّبع األخطاء و التعدٌل على البرنامج صعبة ج ّدا ح ّتى مع استخدام التوابع ففً البرامج الكبٌرة والتً ٌعمل على إنجازها عشرات المبرمجٌن سٌكون من الصعب تقسٌم العمل بحٌث نضمن فصبل تامّا لما سٌقوم به ك ّل مبرمج لذلك ت ّم تصمٌم هذا المبدأ الجدٌد لٌح ّل مح ّل سابقه وقد اع َت َم َد هذا المبدأ على التفكٌر بالبرامج على أ ّنها مجموعة من الكابنات تربط بٌنها عبلقات منطقٌّة معٌّنة تماما كما ٌحدث فً حٌاتنا الٌومٌّة. ما هً الكائنات؟ الكابنات هً األشٌاء! .أجل انظر من حولك فك ّل األشٌاء التً تراها هً كابنات ,وك ّل الكابنات التً تصادفها تمتلك صفات خاصة بها تمٌزها عن غٌرها وقد تمتلك بعض الصفات المشتركة مع كابنات أخرى .لنؤخذ المثال التالً:
إنّ ك ّل مربع من هذه المربعات هو عبارة عن صفّ مستق ٍّل بح ّد ذاته عن اآلخرٌن فً الصفات الخاصّة به )كاالسم والطول ولون البشرة (...وهو ٌشبه البقٌّة فً صفاته العامّة األخرى )كل األحٌاء تتنفّس وتؤكل وتنتقل وتتكاثر .(...وقٌاسا على ذلك ٌمكننا أن نحوّ ل كل األشٌاء التً من حولنا إلى صفوف ونقو َم ببرمجتها لتإدّي الوظابف المطلوبة منها ولتسهٌل هذه العملٌّة سنقوم بكتابة الشٌفرة )التً تحتوي على بٌانات وصفات هذا الصفّ ( ث ّم نستطٌع أن ننشؤ كابنات عدٌدة من هذا الصفّ الذي ّ ٌمثل مرجعا لك ّل الكابنات من نوعه ومثال ذلك ك ٌّل من الج ّد واألب واالبن فً مثالنا السابق هً صفوف مستقلّة لكنّ عصام وخالد هما كابنٌن من صفّ االبن وكل كابن منهما ٌختلف عن الكابن اآلخر فً بعض الصفات. الخبلصة إنّ الصفّ ّ صة ٌمثل المرجع العام للنوع .أ ّما الكابن فهو نسخة من هذا الصفّ ٌمتلك بٌاناته الخا ّ والمختلفة عن باقً الكابنات المنشؤة من هذا النوع. مالحظة :البنٌة األساسٌّة فً البرامج الهٌكلٌّة هً التوابع. أمّا فً البرمجة كابنٌّة التوجّ ه فالبنٌة األساسٌّة هً الصفوف.
233
صف :هو طرٌقة منطق ٌّة لترتٌب البٌانات والتوابع فً بنٌة واحدة. ال ّ ٌصرّ ح عن الصفّ باستخدام الكلمة المحجوزة classوالتً تقابل من الناحٌة الوظٌف ٌّة الكلمة المحجوزة struct فً لغة Cمع قدرتها على احتواء التوابع كؤعضاء ,بدال من احتوابها على بٌانات فقط كما فً structوٌكمننا القول" :إنّ structهو نوع خاص من الصفوف". الصفوف هً أنواع جدٌدة من تعرٌف المستخدم. ٌمكننا أن نعرّ ف الصفّ بالشكل : { class class_name ;member0 permission_label_1: ;member1 permission_label_2: ;member2 ... ;} object_name :classهً كلمة محجوزة ُتستخدم للتصرٌح عن صفّ جدٌد. :class_nameهو اسم الصفّ )النوع من تعرٌف المستخدم(. ٍّ مشتق :object_nameاسم الكابن ال ُمشتق من الصفّ وهو اختٌاري ,و ٌمكن أن ٌكون هناك أكثر من كابن عندها نفصل بٌن أسمابها بفاصلة عاد ٌّة تماما كما فعلنا فً .struct جسم الصفّ ٌمكن أن ٌحتوي على أعضاء واألعضاء إمّا أن تكون تصرٌحات عن بٌانات )متغٌّرات( أو عن توابع ,وهناك مستوى الوصول )السماح( وهو اختٌاريّ وٌكون إحدى الكلمات المحجوزة الثبلث التالٌة: وصول مع ٌّ ٍن وهً تختلف عن private, public, protectdوالتً توضع قبل األعضاء إلكسابها مستوى ٍ بعضها كما سنب ٌّن فً الفقرة التالٌة.
معرفات الوصول Access modifieres ّ ُ ثبلث معرّ فا ٍ ت تحدّد المدى الذي سٌظهر تقدّم C++ما ٌُدعى بمعرّ فات الوصول أو Access modifieresوهً فٌه العضو وهً :
: privateاألعضاء من هذا النوع فً صفّ ما ٌمكن الوصول إلٌها فقط من أعضاء الصفّ نفسه أو من أي صفّ من النوع friendالذي ٌمكن ألعضابه أن ٌصِ لوا إلٌها )األعضاء .(private : protectedاألعضاء من هذا النوع فً صفّ ما ٌمكن الوصول إلٌها من الصفّ نفسه أو من أيّ صفّ من النوع friendوكذلك من أعضاء الصفوف التً ٌت ّم اشتقاقها من هذا الصفّ . : publicاألعضاء فً هذا المستوى ٌمكن الوصول إلٌها من أيّ مكان ٌظهر فٌه الصفّ الذي ٌحوٌها.
مالحظة :لو صرّ حنا عن أعضاء فً صفّ ما قبل أن نضع أيّ معرّ ف وصول فإنّ هذه األعضاء س ُتعتبر من المستوى privateأل ّنه ٌعتبر مستوى الوصول االفتراضً لؤلعضاء التً ٌُصرّ ح آخر. عنها فً أيّ صفّ ما لم نحدّد لها مستوى َ 234
مثال: { class CRectangle ;int x, y public: ;)void set_values (int,int ;)int area (void ;} rect فً هذا المثال قمنا بالتصرٌح عن صفّ )نوع( أسمٌناه CRectangleث ّم أنشؤنا منه كابنا دعوناه .rectهذا الصفّ ٌحتوي أربعة أعضاء ,متغٌّرٌن ) (x, yمن النوع intوهما من المستوى privateأل ّنه المستوى وصول كما قلنا ,و ٌحتوي أٌضا على تابعٌن )(set_values االفتراضً لؤلعضاء إن لم نح ِّدد لها أيّ مستوى ٍ و )( areaفً المستوى , publicو قد صرّ حنا عنهما بالشكل prototypeكما تبلحظ. ّ المشتق منه ,فً المثال السابق اسم الصفّ هو Crectangleالذي الحظ الفرق بٌن اسم الصفّ و اسم الكابن ٌمثل اسم النوع الجدٌد الذي عر ّفناه ,بٌنما اسم الكابن هو rectوهو من نوع الصفّ )أل ّنه اش ُت َّق منه(ٌ .مكن توضٌح هذه المسؤلة من خبلل المثال التالً: ;rect
CRectangle
; CRectangle rect
; a
int
; int a
intهو اسم الصفّ )النوع( ,بٌنما aهو اسم الكابن ال ُم ّ شتق من الصفّ )النوع( .int أثناء كتابة التعلٌمات داخل البرنامج ٌمكننا أن نشٌر إلى أيّ عضو عام )من المستوى (publicللكابن rectكما العضو )كما فعلنا مع struct اسم ِ لو كان تابعا أو متغٌّرا عادٌّا ,وذلك فقط بوضع اسم الكابن متبوعا بنقطة ث ّم ِ فً .(Cمثال: ; )rect.set_value(3,4 ;)(myarea = rect.area لكن ال ٌمكننا أن نفعل ذلك مع العضوٌن x, yأل ّنهما من المستوى الخاص ) (privateأي أ ّنه ال ٌمكن الوصول إلٌهما ّإال من داخل الصفّ CRectangleالذي ُعرِّ فا داخله .إلٌك اآلن المثال كامبل: area: 12
// classes example >#include <iostream ;using namespace std { class CRectangle ;int x, y public: // permission_label_1: ;)void set_values (int,int };)int area (void) {return (x*y ;} { )void CRectangle::set_values (int a, int b ;x = a ;y = b } { )( int main ; CRectangle rect; // like int a ;)rect.set_values (3,4 ;cout << "area: " << rect.area() << endl ;return 0 }
235
الشًء الجدٌد فً هذا المثال هو معامل المدى ::الذي ظهر فً تعرٌف التابع )( set_valuesحٌث اس ُتخدِم من أجل التصرٌح عن العضو )( set_valuesخارج الصفّ الذي عُرِّ ف فٌه. الحظ أ ّننا قمنا بكتابة جسم )سلوك( التابع العضو )( areaداخل الصفّ CRectangleفً حٌن صرّ حنا عن التابع )( set_valuesبالتعرٌف المبدبً للتوابع prototypeكً نستطٌع كتابة جسمه خارج الصفّ .فً هذه عضو ما خارج الصفّ الذي ٌحوٌه ٌجب علٌنا أن نستخدم تابع ٍ الحالة عندما نرغب بكتابة جسم )سلوك( ٍ المعامل .::
معامل المدى :: ٌحدّد هذا المعامل إلى أيّ صفّ ٌنتمً هذا العضو ,وهذا المعامل ٌمنح التصرٌح عن العضو خارج الصفّ نفس صفات المدى للعضو عندما ٌُع ّرف داخل الصفّ . ِب فً المثال السابق استطعنا الوصول إلى المتغٌّرٌن x, yفً التابع )( set_valuesعلما أنّ جسم التابع ُكت َ خارج الصفّ وأ ّنهما عضوٌن فً الصفّ CRectangleوهما من المستوى الخاص) (privateأي أ ّنه ال ٌمكن الوصول إلٌهما ّإال من داخل الصفّ كما أسلفنا سابقا. مثال ٌوضح كٌف ٌمكننا باستخدام هذا المعامل الوصول إلى المتغٌّرات الشاملة فً برنامجنا. 0 0
150 0
// example on Scope Operator :: >#include <iostream ;using namespace std )int x ,y ; //Auto Initializing to 0 (global var's )(int main { ;int x = 150 ;cout<< x << "\t"<< y << endl ;cout<< ::x << "\t" << y << endl ;return 0 }
الفرق الوحٌد بٌن أن تقو َم بكتابة التابع العضو داخل الصفّ بشكل كامل ّ وأال تفع َل ذلك هو أنّ المترجم فً الحالة األولى سٌعتبر التابع من النوع inlineبشكل تلقابً .أمّا فً الحالة الثانٌة )التعرٌف المبدبً( فإنّ المترجم سٌعتبر التابع من النوع الطبٌعً .not-inline
التوابع األعضاء inline كل التوابع األعضاء المعرفة بشكل كامل داخل الصف هً من النوع .inlineلنفترض أن لدٌنا المثال التالً: class Account { private: ;double balance public: } ;Account(double initial_balance) { balance = initial_balance ;)(double getBalance ;) double deposit( double amount ;) double withdraw( double amount ;} 236
التابع Accountوالذي ٌدعى مشٌّدا )انظر الفقرة القادمة( فً هذا المثال هو تابع من النوع inlineأمّا التوابع األخرى مثل )( GetBalance(), Deposite(), Withdrawفهً من النوع الطبٌعً ّ not-inlineإال أ ّنه ٌمكننا أن نحولها إلى توابع من النوع inlineبالشكل التالً : )(inline double Account::getBalance { ;return balance } ) inline double Account::deposit( double amount { ;) return ( balance += amount } ) inline double Account::withdraw( double Amount { ;) return ( balance -= amount } مالحظة :كل التوابع المعرفة بشكل كامل داخل الصف هً من النوع inlineسواء أستخدمنا الكلمة inlineفً التصرٌح عنها أم لم نستخدمها. إنّ التصرٌح عن التوابع على أ ّنها من النوع ٌ inlineجعلها تعمل بؤسلوب مختلف فبدال من استدعابها مثل التوابع العادٌة ٌت ّم نسخ جسم التابع مرّ ة لكل استدعاء وٌن ّفذ كما لو كان جزءا من الشٌفرة التً اس ُتدعً فٌها. ربّما تسؤل نفسك لماذا جعلنا العضوٌن x, yمن المستوى الخاص private؟ )تذ ّكر أ ّنه إذا لم نحدد مستوى الوصول لؤلعضاء فهً من المستوى .(privateالجواب أل ّننا عرّ فنا تابعا )( set_valuesلٌقوم بقراءة قٌمِهما فً محاولة لحماٌتهما من استقبال قٌم خاطبة )نستطٌع أن نكتب شٌفرة داخل التابع للتحقق من صحة البٌانات المدخلة( ولذا فلٌس من حاجة لجعل البرنامج قادرا على التعامل معهما مباشرة .ربّما فً البرامج الصغٌرة والبسٌطة كالمثال السابق لن تجد منفعة كبٌرة من ذلك ,ولكن فً المشارٌع الضخمة قد ٌكون من الضروري جدا أن تبقى قٌم المتغٌّرات بعٌدة عن التحوٌر أو التغٌٌر)قد ٌنتج التغٌٌر عن خطؤ غٌر متوقع أثناء كتابة الشٌفرة .انظر فقرة التغلٌف .(encapsulation من أه ّم مٌزات الصفوف أ ّنه ٌمكننا أن نصرّ ح عن العدٌد من الكابنات منها .فً المثال السابق كان بإمكاننا أن نصرِّ ح عن الكابن )المتغٌّر( rectbباإلضافة إلى الكابن .rect rect area: 12 rectb area: 30
// class example >#include <iostream ;using namespace std { class CRectangle ;int x, y public: ;)void set_values (int,int };)int area (void) {return (x*y ;} { )void CRectangle::set_values (int a, int b ;x = a ;y = b }
237
โ ซ{ )( โ ชint mainโ ฌโ ฌ โ ซ;โ ชCRectangle rect, rectbโ ฌโ ฌ โ ซ;)โ ชrect.set_values (3,4โ ฌโ ฌ โ ซ;)โ ชrectb.set_values (5,6โ ฌโ ฌ โ ซ;โ ชcout << "rect area: " << rect.area() << endlโ ฌโ ฌ โ ซ;โ ชcout << "rectb area: " << rectb.area() << endlโ ฌโ ฌ โ ซ}โ ฌ
โ ซุงู ุญุธ ุฃู ู ุงุงู ุณุชุฏุนุงุก )(โ ช rect.areaโ ฌุงู ู ุนุทู ู ู ุณ ู ุชู ุฌุฉ ุงุงู ุณุชุฏุนุงุก )(โ ช.rectb.areaโ ฌโ ฌ โ ซู ุฐู ู ุฃู ู ู ู ู ู ุงุจู ู ู ู ุด ู ุช ู ู ู ู ู ุงู ุตู ู โ ชู CRectangleโ ฌู ุชู ู ุฃุนุถุงุก ุงู ุตู ู ู ู ู ุง ู ู ุฌุฏู ุฏโ ช .โ ฌุฃู ุฃู ู ู ู ู ุงุจู ู ู ู ู ุงโ ฌ โ ซุตู ู ุจู โ ช ,โ ฌู ุชุงุจุนู ู )(โ ช set_value() , areaโ ฌุฎุงุตู ู ุจู ุฃู ุถุงโ ช.โ ฌโ ฌ โ ซู ุญุชู ู ุนู ู ู ุชุบู ู ุฑู ู โ ช x, yโ ฌุฎุง ู โ ฌ โ ซู ู ู ู ุง ู ุดุคุช ู ู ุฑุฉ ุงู ู ุงุจู ุงุช ู ุงู ุจุฑู ุฌุฉ ู ุงุจู ู ู ุฉ ุงู ุชู ุฌู ู โ ช .โ ฌุญู ุซ ู ุชุนุชุจุฑ ุงู ุจู ุงู ุงุช ู ุงู ุชู ุงุจุน ุฎุตุงุจุต )ุตู ุงุช( ู ู ู ุงุจู โ ช.โ ฌโ ฌ โ ซุณู ู ุงู ุด ู ู ู ู ุฑุงุช ู ุงุฏู ุฉ ู ู ุฒุงุช ู ุฐุง ุงุฃู ุณู ู ุจโ ช.โ ฌโ ฌ โ ซู ู ุญุงู ุชู ุง ุงู ุณุงุจู ุฉ ุงู ุตู ู )ู ู ุน ุงู ุจู ุงู ุงุช ู ู ู ุงุจู ุงุช ุงู ู ุดุช ู ู ุฉ ู ู ู ( ู ู โ ช CRectangleโ ฌุญู ุซ ุฃู ุดุคู ุง ู ู ู ู ุณุฎุชู ู ุฃู โ ฌ โ ซู ุงุจู ู ู ู ู ุง โ ช rect , rectbโ ฌู ู ู ู ู ู ู ู ุง ู ู ุฃุนุถุงุฅู ุงู ุฎุงุตุฉ )ุตู ุงุชู ู ู ู ุชุบู ู ุฑุงุช ู ุชู ุงุจุน(โ ช.โ ฌโ ฌ
โ ซโ ช -2โ ฌุงู ุชุจ ุต ู ู ุง ุฌุฏู ุฏุง ุงุณู ู โ ช Circleโ ฌุจุญู ุซ ู ุญุชู ู ุนู ู ุงุฃู ุนุถุงุก ุงู ุชุงู ู ุฉ โ ช:โ ฌโ ฌ โ ซโ ช ๏ ผโ ฌู ุชุบู ู ุฑ ู ุตู ุงู ู ุทุฑ โ ช.rโ ฌโ ฌ โ ซโ ช ๏ ผโ ฌุชุงุจุน ู ู ุฑุงุกุฉ ู ุตู ุงู ู ุทุฑ )(โ ช. set_radiusโ ฌโ ฌ โ ซ๐ โ ฌ โ ซโ ช ๏ ผโ ฌุชุงุจุน ู ุญุณุงุจ ู ุณุงุญุฉ ุงู ุฏุจุฑุฉ โ ช calc_spaceโ ฌุญู ุซ ุฃู ู ุงู ู ุณุงุญุฉ ู ู โ ฌ โ ซ๐ โ ฌ โ ซโ ช ๏ ผโ ฌุชุงุจุน ุญุณุงุจ ู ุญู ุท ุงู ุฏุงุจุฑุฉ โ ช calc_perimeterโ ฌุญู ุซ ุฃู ุงู ู ุญู ุท ู ู โ ฌ
โ ซโ ช.โ ฌโ ฌ
โ ซโ ช.โ ฌโ ฌ
โ ซุซ ู ู ุงุณุชุฎุฏู ู ู ู ุจุฑู ุงู ุฌู ุญู ุซ ู ุฏุฎู ุงู ู ุณุชุฎุฏู ู ุตู ุงู ู ุทุฑ ู ู ุทุจุน ุงู ุจุฑู ุงู ุฌ ุงู ู ุณุงุญุฉ ู ุงู ู ุญู ุทโ ช.โ ฌโ ฌ โ ซโ ช -3โ ฌุงู ุชุจ ุต ู ู ุง ุงุณู ู โ ช Pointโ ฌุญู ุซ ู ุญุชู ู ุนู ู ุงุฃู ุนุถุงุก ุงู ุชุงู ู ุฉโ ช:โ ฌโ ฌ โ ซโ ช ๏ ผโ ฌู ุชุบู ู ุฑู ู ู ู ุซุจู ู ุงุญุฏุงุซู ุงุช ุงู ู ู ุทุฉ โ ช.x , yโ ฌโ ฌ โ ซโ ช ๏ ผโ ฌุชุงุจุน ุงู ุณุชู ุจุงู ู ู ู ุงู ู ุชุบู ู ุฑู ู ุงู ุณุงุจู ู ู โ ช.set_pointโ ฌโ ฌ โ ซโ ช ๏ ผโ ฌุชุงุจุน ู ุญุณุงุจ ุงู ู ุณุงู ุฉ ุจู ู ู ู ุทุชู ู โ ช distanceโ ฌุญู ุซโ ฌ โ ซโ ช.โ ฌโ ฌ
โ ซโ โ ฌ
โ ซุซ ู ู ุงุณุชุฎุฏู ู ู ู ุจุฑู ุงู ุฌ ู ุญุณุจ ุงู ู ุณุงู ุฉ ุจู ู ู ู ุทุชู ู ู ุญุฏุฏู ู ุง ุงู ู ุณุชุฎุฏู โ ฌ
โ ซโ ช238โ ฌโ ฌ
المش ٌّدات Constructors تحتوي الصفوف على تابع خاصّ ٌدعى المشٌّد constructorالذي ٌص ّرح عنه على أ ّنه تاب ٌع عضو فً الصفّ مرة واحدة فقط وبشكل تلقائً عندما تقوم بإنشاء (اشتقاق) وهو ٌؤخذ نفس اسم الصفّ ٌ .ت ّم استدعاء المش ٌّد ّ الصف وهو أوّ ل تابع ٌت ّم تنفٌذه فً الكابن. نسخة (كائن) جدٌدة من ّ كامل بشكل تحتاج الكابنات عموما إلى تبدبة متغٌّراتها أو حجز ذاكرة دٌنامٌكٌة أثناء عمل ٌّات بنابها لتصبح فعّالة ٍ ٍ فعل ذلك )التبدبة(. ولنتج ّنب القٌم غٌر المتو ّقعة أو العشوابٌّة ألعضابها خبلل فترة تنفٌذ الكابن والناتجة عن عدم ِ مثال :ماذا سٌحدث فً المثال السابق لو أ ّننا استدعٌنا التابع )( areaقبل أن نستدعً التابع )(set_values؟ قد تكون النتٌجة غٌر معروفة )عشوابٌة( ألنّ المتغٌّرٌّن x, yلم ٌُسْ ند إلٌهما أٌّة قٌم ,وفً محاولة للتخلّص من هذه المشكلة سنكتب الصفّ CRectangleوسنضٌف إلٌه مشٌّدا constructor // classes example >#include <iostream ;using namespace std
rect area: 12 rectb area: 30
{ class CRectangle ;int width, height public: CRectangle (int,int); //Constructor };)int area (void) {return (width*height ;} { )CRectangle::CRectangle (int a, int b ;width = a ;height = b } { )( int main CRectangle rect (3,4); //try to remove (3,4) & run ;)CRectangle rectb (5,6 ;cout << "rect area: " << rect.area() << endl ;cout << "rectb area: " << rectb.area() << endl }
كما ترى نتٌجة هذا المثال هً نفس نتٌجة المثال السابق .حٌث قمنا باستبدال التابع )(- set_valuesالذي لم ٌعد موجودا -بالتابع المشٌّد .constructor الحظ كٌف مرّ رنا وسٌطٌن إلى المشٌّد فً نفس اللحظة التً أنشؤنا فٌها نسخة من الصفّ .كاآلتً: ;)CRectangle rect (3,4 ;)CRectangle rectb (5,6 وترى أٌضا أنّ التابع المشٌّد ال ٌمتلك قٌمة معادة كما أ ّنه لٌس من النوع .void
ٌجب أن تضع هذا فً حسبانك دابما المشٌّد الٌعٌد قٌمة ولٌس من النوع .void
أضف مشٌّد ا إلى التمرٌن السابق بحٌث ٌمكنه أن ٌقرأ نصف القطر كوسٌط مباشرة دون الحاجة إلى التابع .set_radius
239
الهادمات Destructors مرة واحد اة عندما الهادم :هو تابع له وظٌفة تعاكس بشكل كامل وظٌفة المشٌّد حٌث ٌت ّم استدعاؤه بشكل تلقائً ّ ٌتحرر الكائن من الذاكرة )إمّا أل ّنه أنهى كل تعلٌماته كؤن نعرِّ ف كابنا على أ ّنه متغٌّر موضعً ضمن تابع ما و ٌنهً التابع ّ تعلٌماته ,أو أل ّنه كابن ت ّم إسناد القٌم المطلوبة إلٌه ث ّم ت ّم تحرٌره من الذاكرة باستعمال معامل الحذف .( delet
الهادم ٌجب أن ٌؤخذ نفس اسم الصفّ مسبوقا بالرمز ~ كما وٌجب ّأال ٌعٌد الهادم قٌمة. ٌستخدم الهادم عادة لتحرٌر الذاكرة -التً ٌحجزها الكابن أثناء تنفٌذه -فً اللحظة التً ٌنهً فٌها الكابن عمله. rect area: 12 rectb area: 30
// example on constructors and destructors >#include <iostream ;using namespace std { class CRectangle ;int *width, *height public: ;)CRectangle (int,int ;)( ~CRectangle };)int area (void) {return (*width * *height ;} { )CRectangle::CRectangle (int a, int b ;width = new int ;height = new int ;*width = a ;*height = b } { )( CRectangle::~CRectangle ;delete width ;delete height } { )( int main ;)CRectangle rect (3,4), rectb (5,6 ;cout << "rect area: " << rect.area() << endl ;cout << "rectb area: " << rectb.area() << endl ;return 0 }
إعادة تحمٌل المش ٌّدات Overloading Constructors كؤيّ تابع آخر ٌمكن تطبٌق هذا المبدأ على المشٌّد وذلك بإنشاء عـ ّدة مشٌّدات لها نفس االسم و تختلف فً عدد أو أنواع الوسطاء) .راجع فقرة إعادة التحمٌل فصل التوابع( وٌستطٌع المترجم أن ٌعرف أيّ هذه التوابع سٌستخدمها الكابن عندما تصرِّ ح عنه. فً الواقع ,عندما ننش ُا ص ّفا وال نع ّرف فٌه أيّ مشٌّد فإنّ المترجم ٌفترض بشكل تلقابً وجود مشٌّدٌن هما المشٌّد العادي )دون وسطاء أو (nopوالمشٌّد النسخة ,مثال : { class CExample public: ;int a,b,c ;} ;void multiply (int n, int m) { a=n; b=m; c=a*b ;} 23:
بما أنّ الصفّ السابق ال ٌمتلك مشٌّدا فإنّ المترجم سٌفترض أنّ هناك مشٌّدٌن افتراضٌٌن هما: المش ٌّد العادي :وهو مشٌّد ال ٌمتلك وسطاء وٌُعْ َرفُ بـ ) nop (no parametersوهو ال ٌفعل أي شًء عادة. ;} { )( CExample::CExample المش ٌّد النسخة ٌ :حتوي على وسٌط من نوع الصفّ ممرّ ر بالمرجع ,وهو ٌقوم بنسخ قٌم المتغٌّرات األعضاء غٌر الثابتة non-staticمن الكابن الوسٌط وٌسندها إلى المتغٌّرات األعضاء المقابلة لها ) (non-staticفً ّ المشتق من صفّ من النوع non-staticأٌضا. الكابن a { )CExample::CExample (const CExample& rv ;a=rv.a; b=rv.b; c=rv.c } ٌجب أن تعلم أنّ المشٌّدٌن االفتراضٌن ٌكونان موجودٌن عندما ال تقوم بالتصرٌح عن أيِّ مشٌّد فً الصفّ و لذلك عندما تضٌف مشٌّدا ما إلى الصفّ فإنّ هذٌن المشٌّدٌن لن ٌكونا موجودٌن وفً حال رغبت باإلبقاء على أحدهما فعلٌك أن تصرّ ح عنه بنفسك. rect area: 12 rectb area: 25
// overloading class constructors >#include <iostream ;using namespace std { class CRectangle ;int width, height public: ;)( CRectangle ;)CRectangle (int,int };)int area (void) {return (width*height ;} { )( CRectangle::CRectangle ;width = 5 ;height = 5 } { )CRectangle::CRectangle (int a, int b ;width = a ;height = b } { )( int main ;)CRectangle rect (3,4 ;CRectangle rectb ;cout << "rect area: " << rect.area() << endl ;cout << "rectb area: " << rectb.area() << endl }
فً هذه الحالة الكابن rectbصُرِّ ح عنه بدون وسطاء ,لذلك فقد تمّت تبدبة متغٌّراته باستخدام المشٌّد العادي nopوالذي ٌسند القٌمة 6إلى ك ّل من المتغٌّرٌن widthو height مالحظة :إذا أردنا أن ننشؤ كابنا جدٌدا من صفّ ما واستخدامنا المشٌّد العادي فعلٌنا أن نذكر اسم الصفّ و بعده اسم الكابن الجدٌد دون أن نضع أقواسا من الشكل )( .أمّا إذا كان فً صفّ ما مشٌّد ات غٌر المشٌّد العادي ) (nopالذي ال ٌمتلك وسطاء لتمرّ ر إلٌه وأردنا استخدام أحدها عندها ٌجب علٌنا أن نذكر القوسٌن )( بعد اسم الكابن الجدٌد وبداخلهما الوسطاء المطلوبة. 241
مثال :فً المثال السابق: رظش٠ؼ طؾ١ؼ ألّٕٔب اعزخذِٕب اٌّشّ١ذ اٌؼبدCRectangle rectb; // ٞ رظش٠ؼ خبؽئ! ّ ألْ اٌّشّ١ذ اٌؼبد ٞل ٠ؾزبط ئٌ ٝاٌمٛعCRectangle rectb(); // )( ٓ١
-2فً التمرٌن ) 1الصفّ (Circleالذي أضفت إلٌه مشٌّد ا لقراءة نصف القطر هل العبارة التالٌة صحٌحة : ; Circle circle -3فً التمرٌن ) 3الصفّ (Pointأضف مشٌّد ٌن األول هو مشٌّد ٌقبل وسٌطٌن من خبلله تصبح قادرا على أن تسند قٌمتً المتغٌّرٌن , x , yو المشٌّد العادي. -4تؤمّل البرنامج التالً:
اجعل البرنامج ٌطبع الشكل التالً:10
>#include<iostream ;using namespace std )(int main { ;"cout<<"Sweat plus sacrifice equals success. ;return 0 }
Give the world the best you have, and the best will come to you. Sweat plus sacrifice equals success. If man hasn’t discovered that he will die for, he isn’t fit to live.
وذلك دون أن تعدّل فً التابع mainأبداا. )تذكر أنّ المتغٌّرات الشاملة تت ّم تبدبتها فً بداٌة البرنامج قبل التابع mainو ٌت ّم هدمها بعد التابع .( main
10
العبارة األولى لـ Madeline Bridgeوالثانٌة لـ , Charles O. Finleyوالثالثة لـ Martin Luther King, JR
242
المؤ ّ شرات على الصفوف Pointers to classes
بشكل حقٌقًٍ ,ولفعل ذلك علٌنا ببساطة أن ُنعرِّ ف مإ ّ ٌمكننا أن ننشا مإ ّ شرا على كابن شرا لٌشٌر على صفّ ما ٍ من نوع الصفّ كما ٌلً: ;CRectangle * prect شر السابق مإ ّ ٌمثل المإ ّ شرا على كابن من النوع ,CRectangleولكً نشٌر بشكل مباشر إلى عضو ما من ضح بعض العبارات الممكنة. أعضاء هذا الكابن ٌنبغً أن نستخدم المعامل > -والمثال التالً ٌو ّ a area: 2 *b area: 12 *c area: 2 d[0] area: 30 d[1] area: 56
// pointer to classes example >#include <iostream ;using namespace std { class CRectangle ;int width, height public: ;)void set_values (int, int };)int area (void) {return (width * height ;} { )void CRectangle::set_values (int a, int b ;width = a ;height = b } { )( int main ;CRectangle a, *b, *c ;]CRectangle * d = new CRectangle[2 ;b= new CRectangle ;c= &a ;)a.set_values (1,2 ;)b->set_values (3,4 ;)d->set_values (5,6 ;)d[1].set_values (7,8 ;cout << "a area: " << a.area() << endl ;cout << "*b area: " << b->area() << endl ;cout << "*c area: " << c->area() << endl ;cout << "d[0] area: " << d[0].area() << endl ;cout << "d[1] area: " << d[1].area() << endl ;return 0 }
وهذه قابمة مختصرة بطرق قراءة المإ ّ شرات والمعامبلت )] [ : (*, &,. , ->, المثال *x &x x.y (*x).y x->y ]x[0 ]x[1 ]x[n
ٌقرأ كاآلتً القٌمة التً ٌشٌر إلٌها المإ ّشر x عنوان الكابن x العضو yمن المإ ّشر x العضو yمن الكابن المشار إلٌه بالمإ ّشر x العضو yمن الكابن المشار إلٌه بالمإ ّشر x الكابن األول الذي ٌشٌر إلٌه المإ ّ شر الكابن الثانً الذي ٌشٌر إلٌه المإ ّ شر الكابن رقم nالذي ٌشٌر إلٌه المإ ّشر
رأ ّوذ ِٓ أّٔه رّ ّىٕذ ِٓ ف ُٙوً ٘زٖ اٌؼٍّ١بد ثشىً ربَٚ ,ئرا وبْ ٌذ٠ه أّ٠خ شىٛن ؽٌٙٛب فٕٕظؾه ثمشاءح فظٍٟ ّ ٚاٌغغالد .struct اٌّإ ّششاد pointers
243
الكلمة المفتاحٌة this اٌظف اٌزُٕ٠ ٞفّز ؽبٌ١بً ٟ٘ٚ .رّضًّ ِإ ّششاً ّ ّ اٌظف رش١ش ئٌ ٝاٌؼٕٛاْ ف ٟاٌزاوشح ٌٍىبئٓ ِٓ ٘زا ٘زٖ اٌىٍّخ داخً لّ١زٗ دائّب ً ػٕٛاْ ٘زا اٌىبئٓ. عضو ما من الكابن هو الكابن نفسه. تابع ٍ ٌمكن أن تستخدم هذه الكلمة لمعرفة فٌما إذا كان الوسٌط الممرر إلى ٍ مثال: yes, &a is b
// this >#include <iostream ;using namespace std { class CDummy public: ;)int isitme (CDummy& param ;} )int CDummy::isitme (CDummy& param { ;if (&param == this) return 1 ;else return 0 } { )( int main ;CDummy a ;CDummy* b = &a ) )if ( b->isitme(a ;"cout << "yes, &a is b\n ;return 0 }
ّ اٌظف ٠ٚؼ١ذ وبئٕب ً ِٕٗ .رزجّغ ػبدحً رغزخذَ ٘زٖ اٌىٍّخ ف ٟاٌّؼبًِ = اٌز٠ ٞمجً ٚع١طب ً ثبٌّشعغ ِٓ ٔفظ ٔٛع اٌّضبي اٌزبٌٚ ٟلؽع و١ف إّٔٔب اعزخذِٕب اٌىٍّخ ٌٍ thisزخٍّض ِٓ اٌّزؾٛي اٌّٛػؼ ٟوّب فؼٍٕب ف ٟاٌّضبي األخ١ش ِٓ اٌفمشح اٌغبثمخ : )CVector& CVector::operator= (const CVector& param { ; x = param.x ; y = param.y ; return *this } ّ طف ئرا ٌُ ٔمُ ٔؾٓ ثاػبدح رؾّ ً١اٌّؼبًِ = ٘ٚزٖ اٌش١فشح ٘ ٟاٌش١فشح الفزشاػ١خ ٌٍّؼبًِ = ِٓ أعً أٞ ٚرغ١١ش اٌش١فشح. مالحظت :األػؼبء ِٓ إٌٛع staticل ّ٠ىٓ أْ ٔش١ش ئٌٙ١ب ثبٌّإ ّشش .this ػٕذِب ُ٠غزذػ ٝػؼِ ٛب ١ٌ -ظ ِٓ إٌٛع ِٓ -staticوبئٓ ّ فاْ ػٕٛاْ اٌىبئٓ ّ ّ٠شس وٛع١ؾ خف ٟئٌ٘ ٝزا اٌؼؼٛ وّب :ٍٟ٠ ;) myDate.setMonth( 3 ٚاٌز٠ ٞؼٕ: ٟ ;) setMonth( &myDate, 3 اٌزؼج١ش (٠ )*thisغزخذَ ػبدح ِٓ أعً ئػبدح اٌىبئٓ اٌؾبٌ ٟومّ١خ ٌٍزبثغ اٌؼؼ ٛوّب فؼٍٕب عبثمبً. 244
.ّخ٠ اٌمذC++ ٔغخٟدح فٛعِٛ غذ١ٌ this اٌىٍّخ:مالحظت : this َػؼ اٌطشق اٌّّىٕخ لعزخذاٛ٠ ِضبي // Example of the this pointer class Date{itn month ; void setMonth(int);} void Date::setMonth( int mn ) { month = mn; // ٘زٖ اٌؼجبساد اٌضالس ِزىبفئخ this->month = mn; (*this).month = mn; } : ٌٟٕب اٌّضبي اٌزب٠ٌٕفزشع أْ ٌذ // this keyword example #include <iostream> using namespace std; class Example { int x; public: void setX(int x){ x = x; } void printX(){cout<< x << endl; } }; int main() { Example ex ; ex.setX(5); ex.printX(); return 0; }
-858993460
// this keyword example #include <iostream> using namespace std; class Example { int x ; public: void set_x(int x) { this->x = x; } void printX(){cout<< x << endl ;} };
5
x ّٛش اٌؼؼ١ّخ اٌّزغ١ لٟ٘ ًطجغ ٘زا اٌجشٔبِظ قٍمتً عشىائٍّت١مخ األِش ع١ ؽمٟما هً وتٍجت هزا انبروامج ؟ ف ّش١ّخ اٌّزغ١ ؟ ٘زا اٌزبثغ لبَ ثاعٕبد لset_x(int x) نكه كٍف؟ و مانزي فعهه انتابعٚ .ّخ١ّخ ل٠ٗ أ١ٌ ٌُ رُغٕذ ئٞاٌز ّ اٌّشىٍخ ٌزٌهٟ٘ ٖؾ؟ ٘ز١عٌّٛش ا١ اٌّزغٛ٘ ّبّٙ٠أٚ ّٛش اٌؼؼ١ اٌّزغٛ٘ ٓ٠ّش١ اٌّزغٞ ّ ٌىٓ أx ّش١ اٌّزغٌٝ ئx ْفا ّ طجغ اٌزبثغ١ّزٗ عشىائٍّت ٌزٌه ع١ثّب أْ لٚ ٗ ٔفغٌٝ ئx ّٛشاٌؼؼ١ّخ اٌّزغ١ ئعٕبد لٟ٘ ّخ١ٍؼزجش ٘زٖ اٌزؼ٠ ُاٌّزشع :ٌٟ اٌّضبي اٌزبٟ نكه ما هى انحم؟ سالت اٌفشق ف.ّخ١ائٛ اٌؼشx ّٛش اٌؼؼ١ّخ اٌّزغ١ لprint
int main() { Example ex ; ex.set_x(5); ex.printX(); return 0; }
245
انصفىف انمع ّرفت باستخذاو انكهمت انمحجىزة struct اٌظف ِ classبػذا ّ ّ أْ أػؼبء اٌغغً رىِٓ ْٛ ٚعّؼذ ِ C++ف َٛٙاٌىٍّخ اٌّؾغٛصح structئٌِ ٝفَٛٙ ّ اٌظف. اٌّغز public ٜٛثشىً افزشاػ ٟثذلً ِٓ أْ رى ِٓ ْٛاٌّغز private ٜٛوّب فٟ ّ اٌظف ٚاٌغغً ٌّٙب ٔفظ اٌٛظبئف رمش٠جب ً فٌ , C++ ٟىٓ ٠ structغزخذَ ػبدح ِٓ أعً ػٍ ٝأ٠خ ؽبي وًٌّ ِٓ اٌج١بٔبد فمؾ أ ِّب classف ٟٙرغزخذَ ِٓ أعً اٌظفٛف اٌز ٟرؾز ٞٛػٍ ٝأػؼبء ِٓ اٌج١بٔبد ٚاٌزٛاثغ ٚ اإلعشاءاد.
إعادة تحمٍم انمعامالث Overloading operators أربؽذ ٌٕب C++اٌخ١بس ف ٟاعزخذاَ ِؼبِالرٙب اٌم١بع١خ ث ٓ١اٌظفٛف اٌز ٟرٕشئٙب أٔذ ثبإلػبفخ ئٌ ٝئِىبّٔ١خ اعزخذاِٙب ث ٓ١األٔٛاع األعبع١خِ .ضبي: ;int a, b, c ;a = b + c ّ٠ىٕه ثبٌزأو١ذ اعزخذاَ ِؼبًِ اٌغّغ +ثِ ٓ١زغّ١ش( ٓ٠وبئٕ ِٓ )ٓ١إٌٛع األعبعٌ ٚ .int ٟىٓ ِبرا ػٓ اٌّضبي اٌزبٌ:ٟ ;struct { char product [50]; float price; } a, b, c ;a = b + c ّ ّ ف ٟاٌٛالغ ل ٠غٛص أْ ٔفؼً رٌه ػٍ ٝاٌشغُ ِٓ ّ اٌظف ٠ؼ ّذ طف ِب ئٌ ٝوبئٓ آخش ِٓ ٔفظ أْ ئعٕبد وبئٓ ِٓ ُ ٌىٓ ػٍّّ١خ اٌغّغ اٌغبثمخ ٘ ٟاٌز ٟعزٕزِظ اٌخطأ ّ أِشاً ِّىٕب ً (ٕ٠غخ اٌّشّ١ذ ثشىً افزشاػّ , )ٟ اٌغّغ غُ ١ش ألْ ِؼبِ ًَ ِ ِزبػ ّئل ث ٓ١األٔٛاع األعبع١خ. ٍ ّئل إّٔٔب ّٔ ٛد ٕ٘ب أْ ٔم ّذَ اٌشىش ئٌ C++ ٝألّٔٙب رّ ّىٕٕب ِٓ ئػبدح رؾِّ ً١ؼبِالرٙب اٌم١بع١خ األِش اٌز٠ ٞغؼٍٕب لبدس َٓ٠ػٍ ٝأْ ٔىزت اٌّضبي اٌغبثك ,فبٌىبئٕبد اٌّشزمّخ ِٓ أٔٛاع ِش ّوجخ وّب ف ٟاٌّضبي اٌغبثك رغزط١غ أْ رمجً اٌّؼبِالد ثؼذ ئػبدح رؾٍّٙ١ب ,وّب عٕى ْٛلبدس ٓ٠ثزٌه ػٍ ٝأْ ٔغّ١ش ف ٟآٌ١خ ػًّ اٌّؼبِالد. ٘زٖ ٘ ٟاٌّؼبِالد اٌزّ٠ ٟىٕٕب أْ ٔؼًّ ػٍٙ١ب رؾّ١الً صائذاً: =<< =&
>> ~ |
=/
<< !
= < > =+ =- =* => ++ -% & ^ =% ][ )( new delete
/ =< ||
* =! &&
== =|
+ =>> =^
246
:خ١ٌ ارّجبع اٌمبػذح اٌزبٌٝبَ ثزٌه ٔؾزبط فمؾ ئ١كٍف وقىو بعمم إعادة انتحمٍم عهى انمعامالث؟ ٌٍم type operator sign(parameters); كما ٌمكننا أن نقوم بكتابة التابع بشكله العادي مباشرة داخلprototype ًوكما تبلحظ فقد التعرٌف المبدب . ّالصف :ً رأخز اٌشىٟاٌزٚ ّخ اٌجؼذ١ذاً ِٓ أعً األشؼّخ صٕبئ٠ذ أْ ٔىزت طفّب ً عذ٠و اآلن لنقل إ ّننا ٔش ⃗ اٌمبػذحٌٝٓ ئ١خؼغ عّغ شؼبػ٠ ش١ ؽ.ٓ١َ ثغّغ شؼبػٛم١ٌ + ًِ اٌّؼبًٍٝ صائذ ػ١َّ ثؼًّ رؾٛذ أْ ٔم٠ ٔشٚ ⃗ ⃗⃗⃗ ⃗ ⃗ ⃗⃗⃗ ⃗ :خ١ٌاٌزب ⃗
⃗⃗⃗
⃗
⃗
⃗⃗⃗
⃗
// vectors: overloading operators example #include <iostream> using namespace std; class CVector { public: int x,y; CVector () {}; CVector (int,int); CVector operator + (CVector); }; CVector::CVector (int a, int b) { x = a; y = b; } CVector CVector::operator+ (CVector param) { CVector temp; temp.x = x + param.x; temp.y = y + param.y; return (temp); } int main () { CVector a (3,1), b (1,2), c; c = a + b; cout<<"a(3,1) + b(1,2) = "; cout<<"c("<< c.x << "," << c.y <<")\n"; return 0; }
:ِضبي
a(3,1) + b(1,2) = c(4,3)
: ّحٍث أن ّ CVector ٌٍظف ّذ١ اعُ اٌزبثغ اٌّش: CVector (int, int); ٟبػ٠ اٌّؼبًِ اٌشًٍٝ ػ١َّ ثاػبدح اٌزؾٛم٠ ٞ ربثغ ِؼبًِ اٌغّغ اٌز: CVector operator+ (CVector); .CVector عٌٕٛذ ا١ؼ٠ ٛ٘ ٚ +
247
ّ٠ىٓ أْ ٔم َٛثبعزذػبء ٘زا اٌزبثغ ثأؽذ اٌشىٍ ٓ١اٌزبٌ:ٓ١١ ;c = a + b أٚ ;)c = a.operator+ (b لؽع أ٠ؼب ً إٔٔب أػفٕب اٌّشّ١ذ اٌؼبد٠ CVector(){ }; ٞؼ ّذ ٘زا أِشاً ػشٚس٠ب ً ع ّذاً ألّٕٔب لّٕب ثزؼش٠ف اٌّشّ١ذ ;)ِ CVector(int, intب ٠ؼٕ ٟأّٔٗ ٌٓ ٠ىٕ٘ ْٛبن أّ٠ب ً ِٓ اٌّشّ١ذ ٓ٠الفزشاػ( ٓ١١ساعغ فمشح اٌّشّ١ذ اد ف ٟاٌذسط اٌغبثك) ٌٚزٌه لثّذ ٌٕب ِٓ ئػبفزٗ ثأٔفغٕب ؽزّ٠ ٝؼًّ اٌجشٔبِظ ,فؼذَ ئػبفزٗ رؼّٕ ٟ ِّىٓ أْ اٌزظش٠ؼ اٌزبٌ CVecotr c; ٟغ١ش ٍ داخً اٌزبثغ )( mainأ ٚغ١شٖ( .ثّٕ١ب ٠ى ْٛاٌزظش٠ؾبْ ا٢خشاْ ِّىٕ ٓ١ثغجت ٚعٛد ِشّ١ذ ٠أخز ٚع١ط)ٓ١ ػٍ ٝأّ٠خ ؽبي ٠ ,غت ػٍ ّ ٟأْ أُػٍِّه أّٔٗ ِٓ األفؼً ػذَ رشن اٌّشّ١ذ اٌؼبد ٞأ nop Constructor ٚثذ ْٚرؼٍّ١بد ألّٔٗ ٚوّب فِ ٟضبٌٕب ٌ ٛإّٔٔب طشؽٕب ػٓ وبئٓ ِب ثبعزخذاَ اٌّشّ١ذ اٌؼبد ّ ٞوب٢ر: ٟ ;CVector c ّ فاْ ل ٌٓ x, y ُ١رىِ ْٛؼشٚفخ (ػشٛائ١خ)ٚ ,ثبٌزبٌ٠ ٟفؼًّ أْ ٔم َٛثٛػغ ثؼغ اٌزؼٍّ١بد اٌز ٟرغبػذٔب ػٍ ٝاٌزؾىُ ثبألػؼبء ٚرجذئزٙب .وّب :ٍٟ٠ ;} ;CVector () { x=0; y=0 ٌُ ٔمُ ثزٌه ف ٟاٌّضبي اٌغبثك ٌٍغٌٛٙخ فمؾ.
وّب ّ أْ اٌظفٛف رؾز ٞٛثشىً افزشاػ ٟػٍِ ٝشّ١ذ( ٓ٠وّب ِش ِؼٕب عبثمبً) ف ٟٙرؾز ٞٛأ٠ؼب ً ػٍ ٝرؼش٠ف ّ اٌظف .ؽ١ش ٠ؼٕ :ٟأِغخ وً األػؼبء غ١ش اٌضبثزخ(ِٓ )non-static ٌّؼبًِ اإلعٕبد = ث ٓ١وبئٕٔ ِٓ ٓ١فظ اٌىبئٓ اٌز ٞػٍ ٓ١ّ٠ ٝاٌّؼبًِ ئٌِ ٝب ٠مبثٍٙب ِٓ أػؼبء اٌىبئٓ اٌز ٞػٍ٠ ٝغبسٖ. ّ٠ ٚىٕه اٌزؾىُ ثزٌه ؽ١ش ّ٠ىٕه أْ رؾذد األػؼبء اٌز ٟرٛد ٔغخٙب. ل رفشع ػٍ١ه ئػبدح رؾّ ً١اٌّؼبِالد أْ رغزخذِٙب ٚفمب ً ٌّؼٕ ً ٝػب ٍَّ أٌ ٚؼالل ٍخ س٠بػٍ ١خ ٚ ,ػٍ ٝاٌشغُ ِٓ رٌه ّ فاْ اعزخذاَ اٌّؼبِالد ٚفمب ً ٌٛظبئفٙب ٠ؼ ّذ أفؼً ,ئر ٌ١ظ ِٓ إٌّطم ٟأْ رؼ١ذ رؾّ ً١اٌّؼبًِ ١ٌ +م َٛثطشػ ِّىٓ ثشِغّ١بً. ّ ٌ وبئٕٔ ِٓ ٓ١فظ إٌٛع ػٍ ٝاٌشغُ ِٓ أْ ٘زا
فً تمرٌن الصفّ pointأعد تحمٌل معامل الجمع لٌقوم بجمع نقطتٌن .حٌث
248
األعضاء الثابتة من النوع static ّ ّ اٌظف" ,ألٔٙب اٌظف ػٍ ٝأػؼبء ِٓ إٌٛع ٚ , staticاٌز ٟرُؼ َشف أ٠ؼب ً ثـ "ِزغّ١شاد ّ٠ىٓ أْ ٠ؾزٞٛ اٌّؾز ٜٛاٌز ٞل ٠ؼزّذ ػٍ ٝأ ٞوبئٓ ٟ٘ٚ .رّضً فمؾ لَِّ١ب ً فش٠ذح ِٛ ٚؽّذح ٌىً اٌىبئٕبد ِٓ ٔفظ إٌٛع. وّضبي ,عٕم َٛثبٌزظش٠ؼ ػٓ ِزغّ١ش ِٓ إٌٛع ٌٕ staticغزخذِٗ ف ٟئؽظبء ػذد اٌىبئٕبد اٌز ٟع١زُ ئٔشبؤ٘ب (٘ذِٙب) خالي اٌجشٔبِظ: 7 6
// static members in classes >#include <iostream ;using namespace std { class CDummy public: ;static int n ;} ;CDummy () { n++ ;} ;~CDummy () { n-- ;} ;int CDummy::n=0 { )( int main CDummy a; // create 1th instance CDummy b[5]; // create 2ed to 6th instances CDummy * c = new CDummy; //create 7th instance cout << a.n << endl; //n = 7 delete c; //delet 7th instance cout << CDummy::n << endl; //n = 6 ;return 0 }
ّ اٌظفٌٙٚ .زا اٌغجت ٌ ٚزغّٕت ف ٟاٌٛالغ رزّزّغ األػؼبء ِٓ ٘زا إٌٛع ثخظبئض اٌّزغّ١شاد اٌشبٍِخ ػٍ ٝوبًِ ّ اٌزظش٠ؼ ػٓ أ ّ اٌظف اٌٛاؽذٚٚ ,فمب ً ٌمٛاػذ ANSI-C++اٌم١بع١خ ّ٠ىٕٕب أْ ٔظ ّشػ ػٕٙب ِٕٙ ٞب ػ ّذح ِ ّشاد فٟ ّ اٌظف ٔٚزشن عغُ اٌزبثغ اٌؼؼ ٛأ ٚئعٕبد اٌم ُ١ئٌ ٝاٌّزغّ١شاد ثبعزخذاَ اٌزؼش٠ف اٌّجذئ prototype ٟداخً ّ اٌظف وّب فؼٍٕب ف ٟاٌّضبي اٌغبثك. خبسط ٌظف األعبعٚ ٟل ٠ز ُّ ٔغخٙب ئٌ ٝاٌىبئٕبد اٌّشزمّخ ّ ّ ألْ ٘زٖ األػؼبء اٌضبثزخ رٛعذ ِٕٙب ٔغخخ ٚاؽذح فمؾ ف ٟا األػؼبء فش٠ذح ِ ٚشزشوخ ث ٓ١عّ١غ اٌىبئٕبد ِٓ ٔفظ إٌٛع ,فّ١ىٕٕب أْ ٔش١ش ئٌ ٝإِٔٙ ٞب وؼؼ ِٓ ٛأ ٞوبئٓ ّ ّ اٌظف ص ُّ اٌّؼبًِ ::ص ُّ اعُ اٌؼؼ ِٓ ٛإٌٛع ( staticؽجؼب ً ٘زا اٌظف ٔفغٗ ٚرٌه ثزوش اعُ أِ ٚجبششح ِٓ اٌشٟء ٠ظٍؼ فمؾ ِٓ أعً األػؼبء ِٓ إٌٛع )staticوّب :ٍٟ٠ ;cout<<a.n ;cout<< CDummy::n ف ٟؽبي وبْ اٌؼؼ ٛربثؼب ً ِٓ إٌٛع staticػٕذئز ّ فاْ ٘زا اٌزبثغ ل ّ٠ىٕٗ أْ ٠زؼبًِ ّئل ِغ اٌّزغّ١شاد ِٓ إٌٛع ّ ّ ثأْ األػؼبء staticل رّزٍه اٌّإشش ّ this .staticوّب ٔزوش ّ ألْ ٘زٖ األػؼبء ل رّضً أػؼبء خبطخ ثبٌىبئٓ ٚئّّٔب ٘ ٟأػؼبء ِشزشوخ ث ٓ١عّ١غ اٌىبئٕبد ِٓ ٘زا إٌٛع.
249
:ً أوجد األخطاء فً البرنامج التال:
class Example { public: Example ( int y = 10 ) : data( y ) { // empty body } // end Example constructor int getIncrementedData() const { return data++; } // end function getIncrementedData static int getCount() { cout << "Data is " << data << endl; return count; } // end function getCount private: int data; static int count; }; // end class Example
24:
الفصل الثامن شصر:
تعتمد البرمجة الكائنٌة على ثالثة مبادئ أساسٌة هً : -2مبدأ التغلٌف .Encapsulation .Inheritance -3الوراثة -4تعدد األشكال .Polymorphism
-1مبدأ التغلٌف Encapsulation تكون ظاهرة لآلخرٌن. صة بصفّ ما وإخفابها ح ّتى ال ٌهدف هذا المبدأ إلى تجمٌع البٌانات الخا ّ َ وللقٌام بذلك فإ ّننا نمنع بٌانات الصفّ )متغٌّراته( من الظهور للمستخدم بشكل مباشر ونق ّدم له عوضا عن ذلك توابع )أو ما ٌعرف فً لغات أخرى مثل javaو C#باسم الطرق (mehodsلتقوم بالتواصل مع بٌانات الصفّ .لنفترض أن لدٌنا المثال التالً : Enter Your age(1 to 110):21 Your age is: 21
>#include<iostream ;using namespace std class Person { public : ;int age ;} )(void main { ;Person my_person ;" cout<<"Enter Your age(1 to 110): ; cin >> my_person.age cout<<"\nYour age is: " << my_person.age ;<< endl }
تستطٌع أن ترى أ ّننا تمك ّنا من الوصول إلى المتغٌّر ageفً الكابن my_personو تخزٌن القٌمة 12فٌه مباشرة وهذه هً المشكلة تصوّ ر أنّ المستخدم أدخل رقما من خارج مجال األعداد الصحٌحة ماذا لو أدخل المستخدم رمزا أو ح ّتى حرفا ؟ فً هذه الحالة سٌحدث خطؤ وقد ٌتسبب بتوقف البرنامج عن العملٌ .بدو مثل هذا الخطؤ مستبعدا فً حالتنا ولك ّنه من المحتمل أن ٌحدث ومه ّمتك عزٌزي المبرمج أن تمنعه من أن ٌحدث. ولكن كٌف ؟ ٌبدو هذا السإال ذكٌا واإلجابة علٌه ستكون سهلة ألنّ ما سنقوم به هو أ ّننا سنعمل تغلٌفا ألعضاء هذا الصفّ بحٌث نمنع بٌاناته )متغٌّراته( من الظهور للمستخدم بشكل مباشر وسنقدّم له بدال من ذلك إحدى الطرٌقتٌن التالٌتٌن:
251
: private للوصول إلى أعضاءpublic استخدام توابع-a #include<iostream> using namespace std; class Person { int m_age ; public : void SetAge(int p_age) { if (p_age > 100 || p_age < 1) { cout<< "you can't edit age like that"; m_age =1 ; } else { m_age = p_age; cout<< "done "; } } int GetAge() { return m_age; } }; void main() { Person my_person; int my_age =0; cout<<"Enter Your age(1 to 110): "; cin>> my_age; my_person.SetAge(my_age) ; cout<<"\nYourage is: "<<my_person.GetAge() << endl; }
Enter Your age(1 to 110):21 done Your age is: 21
أضف المشٌّد التالً إلى البرنامج السابق )ال تنس أنّ المشٌّد العادي لن ٌكون موجودا بعدها: استخدام المش ٌّد ات-b (ح ّتى تضٌفه بنفسك
Person(int p_age) { if (p_age > 100 || p_age < 1) { cout<< "you can't edit age like that"; m_age =1 ; } else { m_age = p_age; cout<< "done"; } }
252
قبل الحدٌث عن الوراثة لنتعرّ ف على التوابع الصدٌقة ألنها مهمّة لنا فً دراسة الوراثة
التوابع ( friendالكلمة المفتاحٌة )friend ٔؼٍُ ّ أْ ٕ٘بن صالصخ ِؼشّفبد ٚطٛي ٘ٚ private, public, protected :ٟلٍٕب ف ٟاٌؾبٌخ اٌز٠ ٟى ْٛفٙ١ب ػؼٛ ّ اٌظفٚ .ػٍ ٝاٌشّغُ ِٓ رٌه ِب ِٓ أؽذ اٌّغز private ٓ١٠ٛأ protected ٚفال ّ٠ىٓ اٌٛطٛي ئٌ ِٓ ٗ١خبسط ّ اٌظف ,ػٕذ٘ب ّ٠ىٓ اٌٛطٛي ئٌ٘ ٝزا ّ٠ىٕه أْ رزؼ ّذ٘ ٜزٖ اٌمبػذح ثبعزخذاَ اٌىٍّخ اٌّؾغٛصح friendفٟ ّ ّ اٌظف اٌظفٌٚ .فؼً رٌه ػٍ١ه فمؾ أْ رظشّػ ػٓ اٌؼؼ ٛاٌز ٞرش٠ذ اٌٛطٛي ئٌ ِٓ ٗ١خبسط اٌؼؼ ِٓ ٛخبسط ثبعزخذاَ اٌزؼش٠ف اٌّجذئ prototype ٟص ُّ رزوش ٘زٖ اٌىٍّخ أِبِِٗ .ضبي: 24
// friend functions >#include <iostream ;using namespace std { class CRectangle ;int width, height public: ;)void set_values (int, int };)int area (void) {return (width * height ;)friend CRectangle duplicate (CRectangle ;} { )void CRectangle::set_values (int a, int b ;width = a ;height = b } )CRectangle duplicate (CRectangle rectparam { ;CRectangle rectres ;rectres.width = rectparam.width*2 ;rectres.height = rectparam.height*2 ;)return (rectres } { )( int main ;CRectangle rect, rectb ;)rect.set_values (2,3 ;)rectb = duplicate (rect ;cout << rectb.area() << endl }
من تعرٌف التابع duplicateنجد أنه من النوع friendفً الصفّ ,CRectangleما ٌجعلنا قادرٌن على الوصول إلى المتغٌّرٌن widthو heightعلما أ ّنهما من المستوى privateوذلك من أي كابن من النوع .CRectangle الحظ أ ّننا لم نعتبر التابع duplicateعضوا من الصفّ CRectangleال فً التصرٌح عنه وال فً االستخدام األخٌر فً التابع )( .mainكما ٌمكن له أن ٌؤخذ المستوى العام publicأو الخاص privateفهذا لن ٌإثر على استخدامنا له. ٌمكن استخدام التوابع من هذا النوع من أجل القٌام بعملٌات على ص ّفٌن من نوعٌن مختلفٌن .عموما هذا االستخدام لٌس من مبادئ البرمجة كابنٌة التوجه OOPلذلك من األفضل استخدام أعضاء من ضمن الصفّ فمثبل سٌكون من المفٌد )بغرض اختصار الشٌفرة( فً المثال السابق لو قمنا بكتابة التابع duplicateبشكل كامل على أنه عضو من الصفّ .CRectangle 253
friend الصفوف من النوع ً كصدٌق لصفّ آخر كما فعلنا فً التوابع من هذا النوع فfriend ٌمكننا أن نص ّرح عن صفّ من النوع من الوصول إلى كا ّفة أعضاء الصفّ اآلخر ح ّتى التً منfriend الفقرة السابقة ممّا ٌم ّكن الصفّ الصدٌق : مثال.protected أوprivate المستوى // friend class #include <iostream> using namespace std; class CSquare; class CRectangle { int width, height; public: int area (void) {return (width * height);} void convert (CSquare a); }; class CSquare { private: int side; public: void set_side (int a) {side=a;} friend class CRectangle; }; void CRectangle::convert (CSquare a) { width = a.side; height = a.side; } int main () { CSquare sqr; CRectangle rect; sqr.set_side(4); rect.convert(sqr); cout << rect.area() << endl; return 0; }
16
ّ لذلك فإنCSquare ّ للصفfriend على أ ّنه صدٌقCRectangle ّصرّ حنا فً هذا المثال عن الصف .CSquare ّ ٌمكنه الوصول إلى كل أعضاء الصفCRectangle ّالصف ّ غرٌبة بعض الشًء فً الواقعclass CSquare ; ربما تجد التعلٌمة ًتمثل هذه التعلٌمة التصرٌح المبدب ولو لمconvert() أل ّننا استخدمنا هذا الصفّ كوسٌط فً التابعCSquare ّ عن الصفprototype ّنقم بالتصرٌح عنه بهذا الشكل لكان من غٌر الممكن استدعاإه كوسٌط فً هذا التابع من الصف .CRectangle ما ٌعنً أنّ بإمكانه أنCSquare ّ للصفfriend صدٌقCRectangle ّفً حالتنا هذه اعتبرنا أن أوprivate ح ّتى ولو كان من المستوىCSquare ٌّصل إلى أيّ عضو موجود فً الصف صدٌقاSCquare ّممكن علما أ ّنه ال شًء ٌمنعنا من أن نجعل الصف العكس غٌ ُر ّ و لكنprotected َ ٍ .CRectangle ّ للصفfriend
254
-2الوراثة بٌن الصفوف Inheritance between classes
آخر )أبٍ( حٌث تع ّد الوراثة ص ّفة مه ّمة من صفات الصفوف .فهً تسمح لنا بإنشاء كابنا )ابنا( مشت ّقا من كابن َ ٍ ٌصبح الكابنُ االبنُ حاوٌا على بعض صفات )خصابص( الكابن األبّ باإلضافة إلى صفاته األساسٌة) .الصفات هً األعضاء العالمّة المعرّ فة فً الصفّ والتً تسمح بالتعامل معه( .لنؤخذ مثاال على ذلك: لنفترض أ ّننا أردنا أن ننشا مجموعة من الصفوف تصف األشكال الهندس ٌّة ذوات األضبلع polygonsكالتً أنشؤناها سابقا مثل CRectangleأو .CTriangleهذه األشكال تمتلك بعض الصفات األساس ٌّة المشتركة بٌنها جمٌعا ,فك ٌّل هذه األشكال تمتلك قاعدة )عرض( وارتفاع. لذلك سنقوم بالتصرٌح عن صفّ ٌحوي الصفات المشتركة )عرض و ارتفاع( لك ِّل األشكال المضلّعة وسنسمٌه CPolygonحٌث أنّ كل شكل مضلّع ٌستطٌع أن ٌرث صفاته األساس ٌّة من الصفّ .CPolygonكما فً الشكل:
الصفوف التً ُتش َت ّق من الصفوف األساسٌّة ترث جمٌع أعضابها الظاهرة .وهذا ٌعنً أ ّنه لو كان الصفّ األساسًّ ٌمتلك عضوا Sولو صنعنا ص ّفا ّ جدٌدا فٌه العضو Bوٌرث الصفّ األساسًّ فإنّ الصفّ الجدٌد سٌمتلك العضوٌن Sو Bمعا. ا وراثة بٌن ص ّفٌن؟ ٌت ّم ذلك باستخدام المعامل ) ( :الذي ٌُخبر المترجم بؤنّ الصفّ الذي كٌف ٌمكننا أن نجري قبل )على ٌسار( هذا المعامل سٌرث الصفّ الذي بعده )على ٌمٌنه( .بالطرٌقة التالٌة: ;class derived_class_name : public base_class_name حٌث أن : :derived_class_nameاسم الصفّ المشتق. :base_class_nameاسم الصفّ األساسً. :publicمعرّ ف الوصول ٌمكن أن ٌُستب َدل بؤيٍّ من المعرّ فٌن اآلخرٌن ) .(private, protectedوسنتعرّ ف على فابدته بعد المثال: 20 10
// derived classes >#include <iostream ;using namespace std { class CPolygon protected: ;int width, height public: )void set_values (int a, int b };{ width=a; height=b ;} { class CRectangle: public CPolygon public: )int area (void } ;){ return (width * height ;}
255
{ class CTriangle: public CPolygon public: )int area (void } ;){ return (width * height / 2 ;} { )( int main ;CRectangle rect ;CTriangle trgl ;)rect.set_values (4,5 ;)trgl.set_values (4,5 ;cout << rect.area() << endl ;cout << trgl.area() << endl ;return 0 }
كما ترى فإنّ ّ كبل من الص ّفٌن CRectangleو ٌ CTriangleحتوي على األعضاء )( width, height, set_valuesالموجودٌن أساسا فً الصفّ .CPolygon ّ نشتق )نرث( الصفوف من بعضها. الكلمة protectedمشابهة للكلمة privateوالفرق الوحٌد ٌحدث عندما ّ نشتق )نرث( ص ّفا من صفّ ما آخر فإنّ األعضاء من النوع protectedالموجودة فً الصفّ األساسً عندما ٌمكن الوصول إلٌها من قبل أعضاء الصفّ الجدٌد بٌنما تلك التً من النوع privateفبل ٌمكن الوصول إلٌها ّإال من خبلل الصفّ األساسًّ نفسه. و ألننا نرٌد أن نتعامل مع ك ٍّل من العضوٌن width, heightمن خبلل الصفوف الجدٌدة المشت ّقة من الصفّ CPolygonلذلك صرّ حنا عنهما على أ ّنهما من النوع .protected الحظ الجدول التالً الذي ٌح ِّدد الفرق بٌن مع ّرفات الوصول. إمكانٌة الوصول إلى صف األعضاء من نفس ال ّ األعضاء من الصفوف المشتقة
public
protected
private
فً مثالنا ,األعضاء الموروثة فً ك ّل من الص ّفٌن CTriangle, CRectangleتتبع نفس مستوٌات الوصول فً الصفّ األساسً .CPolygon CPolygon::width // protected access CRectangle::width // protected access CPolygon::set_values() // public access CRectangle::set_values() // public access وذلك أل ّننا استخدمنا المعرف publicالشتقاقهما )لٌرثا( من الصفّ CPolygonكما ٌلً : ;class CRectangle : public CPolygon إنّ الكلمة المفتاحٌة ّ public تمثل أدنى مستوى من الحماٌة لؤلعضاء الموروثة من الصفّ األساسًّ وٌمكن تغٌٌر هذا المستوى لٌكون أحد المستوٌٌن اآلخرٌن .كمثال لنفترض أ ّننا عرّ فنا الصفّ الجدٌد daughter ّ المشتق من الصفّ األساسًّ motherوفق المستوى protectedكاآلتً: ;class daughter : protected mother هذا ما سٌجعل المستوى protectedهو المستوى األدنى لحماٌة أعضاء الصفّ األساسً ألنّ ك ّل أعضابه التً كانت من النوع publicفً الصفّ motherستصبح من النوع protectedفً الصفّ .daughter صة به من النوع publicألنّ التغٌٌر فً بالطبع هذا ال ٌمنع من أن ٌحوي الصفّ daughterعلى أعضاء خا ّ مستوى الوراثة سٌطبق على أعضاء الصفّ األساسًّ motherفقط. 256
أمّا استخدام الكلمة privateف ٌُعتبر األكثر انتشارا بعد الكلمة publicوذلك أل ّنها تإ ِّمن تغلٌفا كامبل ألعضاء الصفّ األساسً حٌث ال ٌمكن الوصول إلى أعضاء الصفّ األساسً ّإال من داخله. على ك ٍّل إذا لم تذكر معرّ ف الوصول بشكل صرٌح أثناء تعلٌمة الوراثة فإنّ المعرّ ف االفتراضً هو private وذلك من أجل الصفوف المعرّ فة باستخدام الكلمة ,classأ ّما تلك المعرفة باستخدام الكلمة structفإنّ المعرّ ف االفتراضً لها هو .public صف األساسً؟ بحسب مبادئ الوراثة فإنّ ك ّل أعضاء الصفّ األساسً ما هً األشٌاء التً ٌت ّم وراثتها من ال ّ ستورَّ ُ ّ )المشتق( ما عدا األعضاء التالٌة: ث إلى الصفّ االبن Constructor and destructor operator=() member friends على الرغم من أنّ المشٌّد والهادم ال تت ّم وراثته ّإال أ ّنه سٌت ّم استدعاء المشٌّد االفتراضً )كالمشٌّد العادي مثبل( ّ مشتق من الصفّ األساسًّ .أمّا إذا لم ٌكن فً الصفّ أو الهادم من الصفّ ألساسً عند إنشاء أو هدم أيّ صفّ األساسًّ مشٌّد افتراضً )أل ّنك قمت بإعادة تحمٌل المشٌّد بطرٌقة ما( و أردت أن ٌت ّم استدعاء المشٌّد الجدٌد فً ك ّل مرّ ة ٌت ّم فٌها إنشاء صفّ جدٌد فعلٌك أن تصرّ ح عن ذلك بالشكل : }…{ (derived_class_name )parameters( : base_class_name )parameters mother: no parameters daughter: int parameter mother: int parameter son: int parameter
// constructors and derivated classes >#include <iostream ;using namespace std { class mother public: )( mother } ;"{ cout << "mother: no parameters\n )mother (int a } ;"{ cout << "mother: int parameter\n ;} { class daughter : public mother public: )daughter (int a };"{cout<< "daughter: int parameter\n\n ;}
{ class son : public mother public: )son (int a) : mother (a } ;"{ cout << "son: int parameter\n\n ;} { )( int main ;)daughter x (1 ;)son y (1 ;return 0 }
257
راقب الفرق بٌن المشٌّد من الصفّ األساسً الذي ت ّم استدعاإه عندما أنشؤنا الكابن xمن الصفّ daughterو المشٌّد الذي ت ّم استدعاإه عندما أنشؤنا الكابن yمن الصفّ sonهذا الفرق سببه أ ّننا عرّ فنا المشٌّد فً الصفّ daughterبالشكل التالً: )daughter (int a فً هذه الحالة سٌت ّم استدعاء المشٌّد االفتراضً من الصفّ األساسً وهو )( motherوذلك أل ّننا لم نخبر المترجم أيّ المشٌّدات علٌه أن ٌستدعٌه فهو ٌقوم باستدعاء المشٌّد االفتراضً. أ ّما فً الصفّ sonفإنّ المشٌّد كان بالشكل التالً: )son (int a) : mother (a فً هذه الحالة أخبرنا المترجم أنّ علٌه أن ٌستدعً المشٌّد الذي ٌقبل وسٌطا من النوع intوذلك باستخدام المعامل :عند التصرٌح عن المشٌّد فً الصفّ الجدٌد.
الوراثة المتعددة
Multiple inheritance
ٌمكنك فً C++أن تصنع ص ّفا ٌرث صفاته من أكثر من صفّ فً نفس الوقت وهذا ٌشبه تماما ما ٌحدث لئلنسان فكلنا ٌعلم أنّ الصفات التً تكون فً المولود الصغٌر بعضُها قاد ٌم من األب و بعضُها اآلخر من األم أي أ ّنه لو افترضنا أنّ لدٌنا ص ّفا ٌمثل المولود وآخر ّ ٌمثل األب وثالث ٌمثل األم فإنّ بإمكان الصفّ المولود أن ٌرث من األب واألم معا .تت ّم هذه العملٌة بؤن نضع فاصلة ) ( ,بٌن أسماء الصفوف التً نرٌد من الصفّ الجدٌد أن ٌرثها كما ٌلً: ; class derived_class_name : public base_class_name1 , base_class_name2 مثال آخر ,لو عرّ فنا ص ّفا جدٌدا أسمٌناه COutputو أردنا من الص ّفٌن CTriangle, CRectangleأن ٌرثا الصفات الموجودة فً هذ الصفّ باإلضافة إلى تلك التً ورثاها سابقا من الصفّ CPolygonفبإمكاننا أن نكتب عندها : { class CRectangle : public CPolygon, public COutput { class CTriangle : public CPolygon, public COutput إلٌك المثال كامبل: 20 10
// multiple inheritance >#include <iostream ;using namespace std { class CPolygon protected: ;int width, height public: )void set_values (int a, int b };{ width=a; height=b ;} { class COutput public: ;)void output (int i ;}
258
void COutput::output (int i) { cout << i << endl; } class CRectangle: public CPolygon, public COutput { public: int area (void) { return (width * height); } }; class CTriangle: public CPolygon, public COutput { public: int area (void) { return (width * height / 2); } }; int main () { CRectangle rect; CTriangle trgl; rect.set_values (4,5); trgl.set_values (4,5); rect.output (rect.area()); trgl.output (trgl.area()); return 0; }
Polymorphism تعدد األشكال-3 ٌسمح هذا المبدأ بكتابة صفّ ٌحتوي على الهٌكل العام للصفّ من دون أٌّة تعلٌمات )تضمٌنات( لكً ٌجبر .المبرمجٌن الذٌن سٌشت ّقون هذا الصفّ على تضمٌن الكابنات التً ٌنشإنها من هذا الصفّ من جدٌد ّ من أجل فهم أفضل للفقرات التالٌة ننصح بالتم ّكن من المفاهٌم التالٌة )المإ إذا.( شرات – الوراثة بٌن الصفوف : كانت إحدى العبارات التالٌة غٌر مفهومة عندك ننصحك بالتم ّرن على المفاهٌم السابقة الذكر بشكل أفضل int a::b(c) {}; // Classes a->b // pointers and objects class a: public b; // Relationships between classes
ّ المؤ Pointers to base class ًصف األساس ّ شرات على ال ّ واحدة من أه ّم المٌزات التً نحصل علٌها باشتقاق أصناف جدٌدة من أصناف أساسٌّة هً أنّ المإ ٍّشر على أي ّ من األصناف المشت ّقة متوافق مع مإ .شر على الصفّ األساسً الذي اش ُت ّق منه هذا الصف سنقوم بكتابة برنامج, كمثال.C++ هذه الفقرة مخصّصة بالكامل للحدٌث عن قوّ ة هذه المزاٌا التً تقدمها : األشكال الهندسٌة السابق باستخدام هذه المزٌّة // pointers to base class #include <iostream> using namespace std; class CPolygon { protected: int width, height; public: void set_values (int a, int b) { width=a; height=b; } }; class CRectangle: public CPolygon { public: int area (void)
259
20 10
} ;){ return (width * height ;} { class CTriangle: public CPolygon public: )int area (void } ;){ return (width * height / 2 ;} { )( int main ;CRectangle rect ;CTriangle trgl ;CPolygon * ppoly1 = &rect ;CPolygon * ppoly2 = &trgl ;)ppoly1->set_values (4,5 ;)ppoly2->set_values (4,5 ;cout << rect.area() << endl ;cout << trgl.area() << endl ;return 0 }
فً التابع الربٌسً )( mainأنشؤنا مإ ّ شرٌن * ppoly1 , * ppoly2على كابنٌن من الصفّ .CPolygon و أسندنا ألٌهما عنوانً الكابنٌن rect, trglوأل ّنهما كابنٌن من ص ّفٌن مشت ّقٌن من الصفّ األساسًّ CPolygon فإنّ هذا اإلسناد ممكن .نستطٌع أن نستخدم المإ ّ شرات من نوع الصفّ األساسً لنشٌر بها على األعضاء الموروثة فً الصفوف المشت ّقة منه فقط لذلك لم نقم باستخدامهما فً استدعاء التابع )( areaوقمنا باستدعابه بالطرٌقة المعتادة.
األعضاء من النوع virtual فً المثال السابق كً نستطٌع التؤشٌر على التابع )(ٌ areaجب أن نجعله عضوا فً الصفّ األساسً ولكن هذا سٌتسبب بمشكلة جدٌدة هً أنّ كبل من الص ّفٌن ٌ CRectangle, CTriangleرثان صفاتهما من الصفّ األساسً و التابع )( areaهو واحد من هذه الصفات ّإال أنّ مساحة المستطٌل ناتجة عن ضرب الطول بالعرض ,ومساحة المثلث ناتجة عن ضرب الطول بالعرض وتقسٌم الناتج على ,3فما هو الحل؟. الحل ٌكمن فً أن نقوم بكتابة التابع )( areaفً كل من الصفٌّن CRectangle, CTriangleولكً نصبح قادرٌن على التؤشٌر علٌهما باستخدام مإ ّ شر من نفس نوع الصفّ األساسً سنقوم بتعرٌفه فً الصفّ األساسً ّ أٌضا لكن سٌكون تعرٌفه من نوع خاصّ هو النوع ,virtualث ّم نقوم بتعرٌفه بنفس االسم فً ك ّل من الصفٌن CRectangle, CTriangleونقوم بكتابة التعلٌمات المناسبة لك ّل منهما من جدٌد وهذا ما ٌُعرف بإعادة القٌادة .Overriding إذن األعضاء من النوع virtualهً األعضاء المشتركة التً نرغب بؤن ترثها كل الصفوف المشتقة من الصفّ األساسً والتً سنعٌد كتابة تعلٌماتها ) (overridingداخل بعض أو كل الصفوف التً ترث الصفّ األساسً. و بعد التعدٌل ٌصبح المثال بالشكل: 20 10 0
// virtual members >#include <iostream ;using namespace std { class CPolygon protected: ;int width, height public: )void set_values (int a, int b } ;{ width=a; height=b )virtual int area (void } ;){ return (0
25:
;} { class CRectangle: public CPolygon public: )int area (void } ;){ return (width * height ;} { class CTriangle: public CPolygon public: )int area (void } ;){ return (width * height / 2 ;} { )( int main ;CRectangle rect ;CTriangle trgl ;CPolygon poly ;CPolygon * ppoly1 = &rect ;CPolygon * ppoly2 = &trgl ;CPolygon * ppoly3 = &poly ;)ppoly1->set_values (4,5 ;)ppoly2->set_values (4,5 ;)ppoly3->set_values (4,5 ;cout << ppoly1->area() << endl ;cout << ppoly2->area() << endl ;cout << ppoly3->area() << endl ;return 0 }
تستطٌع أن ترى اآلن أنّ ّ كبل من الصفوف ( )CPolygon, CTriangle, CRectangleتمتلك نفس األعضاء ( )(.) width, height, set_value(), area و اآلن جرّ ب أن تزٌل الكلمة المحجوزة virtualث ّم ش ّغل البرنامج ,ماذا ترى؟ النتٌجة ستكون 0فً الحاالت الثبلث بدال من ,20, 10, 0ولكن لماذا؟ أل ّنك عندما أزلت الكلمة virtualمن أمام التصرٌح عن التابع )( areaفً الصفّ CPolygonث ّم استخدمت مإ ّ شرا من نوع هذا الصفّ لتشٌر إلى التابع )( areaفً ك ّل من الكابنٌن rect , trglفإنّ المإ ّ شر سٌشٌر إلى التابع فً الصفّ األساسً والذي ٌعٌد القٌمة ّ كما هو واضح من تعرٌفه أمّا الكابن polyفهو أصبل من النوع CPolygonوالتابع المعرّ ف فٌه ٌعٌد 0دابما. إنّ ما تفعله هذه الكلمة هو أ ّنها تسمح باستدعاء العضو من الصفّ المشتق والذي ٌمتلك نفس اسم العضو فً الصفّ األساسً عندما ٌستخدم المإ ّ شر ,كما فً المثال السابق. ال ٌقتصر األمر فقط على استخدام المإ ّ شرات ففً هذه الحالة التابع )( areaهو أصبل من الصفات المشتركة فً كل األشكال الهندسٌة المضلّعة المغلقة لذلك علٌنا أن نقوم بوضعه فً الصفّ األساسً CPolygonوألنّ طرٌقة حساب مساحة كل شكل تختلف عن الطرق األخرى فإ ّننا نصرّ ح عن التابع )( areaفً الصفّ األساسًّ على أ ّنه من النوع virtualث ّم نعٌد قٌادته فً الصفوف المشت ّقة. ومثال ذلك لو افترضنا أنّ لدٌنا ص ّفا أساسٌّا للمركبات ث ّم اشت ّقٌنا منه ص ّفا للسٌارة وآخر للدراجة النارٌة ,معلو ٌم أنّ ك ّل المركبات تستخدم الوقود لكً تسٌر لذلك سنعرّ ف التابع )( fuelفً الصفّ األساسً لٌحسب كمٌة الوقود البلزمة لقطع مسافة معٌّنة لكن هل تستهلك السٌارة نفس الكمٌة من الوقود التً تستهلكها الدراجة لتقطعا نفس المسافة؟ بالطبع ال و هذا االختبلف ٌجعل من األفضل أن نستخدم الكلمة virtualلنعٌد قٌادة التابع )( fuelضمن الصفّ المشتق كلّما دَ َعت الحاجة لذلك.
261
// virtual members #include <iostream > using namespace std; class Vehicle { protected: float distance ; public: Vehicle() { distance = 0.0; } void SetDistance(float d) { distance = d; } virtual float fuel() { return distance/5; } }; class Car: public Vehicle { public: float fuel() { return distance/10; } }; class Cycle:public Vehicle { public: float fuel() { return distance/15; } }; int main() { Vehicle myvehicle; Car mycar; Cycle mycycle; myvehicle.SetDistance(10); mycar.SetDistance(10); mycycle.SetDistance(10); cout<<"Vehikle need: "<<myvehicle.fuel() <<" leters of fuel in 10 KM\n"; cout<<"Car need: "<<mycar.fuel() <<" leters of fuel in 10 KM\n"; cout<<"Cycle need: "<<mycycle.fuel() <<" leters of fuel in 10 KM\n"; return 0; }
262
Vehikle need: 2 leters of fuel in 10 KM Car need: 1 leters of fuel in 10 KM MotoCicle need: 0.666667 leters of fuel in 10 KM
الصفوف األساس ٌّة المجردة Abstract base classes الصفوف المجرّ دة البسٌطة هً ص ّفوف تشبه إلى ح ّد كبٌر الصفّ CPolygonالذي أنشؤناه سابقا والفرق البسٌط ٌكمن فً التابع )( areaالمعرّ ف فً الصفّ CPolygonحٌث ال ٌمكن للص ّفوف المجرّ دة أن تحوي على تعلٌمات فً توابعها التً من النوع virtualوبدال من كتابة التابع بك ّل تعلٌماته فً الصفّ األساسً سنكتفً فقط بالتصرٌح عن التابع دون كتابة أيّ تعلٌمة فٌه ولن نضٌف له األقواس }{ أٌضا لكن ٌمكننا فً حالتنا هذه أن نضٌف إلى التعرٌف قٌمة ابتدابٌة لٌعٌدها التابع وذلك بإضافة اإلسناد التالً: ; virtual int area (void) = 0 لٌصٌر عندها شكل الصفّ CPolygonكاآلتً: // abstract class CPolygon { class CPolygon protected: ;int width, height public: )void set_values (int a, int b } ;{ width=a; height=b ;virtual int area (void) =0 ;} الحظ كٌف أ ّننا أضفنا المساواة = 0إلى التعرٌف عن التابع عوضا عن كتابة جسمه كامبل .هذا النوع من التوابع ٌدعى ,pure virtual functionوك ّل الصفوف التً تحتوي على مثل هذا النوع من التوابع تدعى صفوفا مجرّ دة .abstract classes االختبلف األكبر لهذه الصفوف عن غٌرها أ ّنه ال ٌمكننا أن ننشا منها نسخا جدٌدة فهً غٌر قابلة لبلشتقاق, لك ّنه ٌمكننا أن نشٌر إلٌها باستخدام مإ ّ شر . عند ذلك فإن التعلٌمة : ; CPolygon poly غٌر صحٌحة ألنّ الصفّ CPolygonأصبح اآلن من النوع المجرّ د .abstract class لكن ٌمكننا أن نقوم بالتصرٌحٌن اآلتٌٌن: ;CPolygon * ppoly1 ;CPolygon * ppoly2 وهذا ألنّ التوابع من النوع pure virtual functionال تحتوي على تعلٌمات بداخلها وهذا ٌجعل من المستحٌل إنشاء ُنسخ من الصفّ المجرّ د إذ أنّ بعض أعضابه ال تمتلك تعرٌفات كاملة لوظابفهاّ ,إال أ ّنه ٌمكننا أن نشٌر إلى الصفّ الذي ٌرث الصفّ األساسً المجرّ د باستخدام مإ ّ شر كما فً المثال التالً: 20 10
// virtual members >#include <iostream ;using namespace std { class CPolygon protected: ;int width, height public:
263
void set_values (int a, int b) { width=a; height=b; } virtual int area (void) =0; }; class CRectangle: public CPolygon { public: int area (void) { return (width * height); } }; class CTriangle: public CPolygon { public: int area (void) { return (width * height / 2); } }; int main () { CRectangle rect; CTriangle trgl; CPolygon * ppoly1 = &rect; CPolygon * ppoly2 = &trgl; ppoly1->set_values (4,5); ppoly2->set_values (4,5); cout << ppoly1->area() << endl; cout << ppoly2->area() << endl; return 0; }
لو أعدت النظر فً المثال السابق لرأٌت أ ّننا استطعنا أن نشٌر إلى كابنات من أنواع )صفوف( مختلفة باستخدام ّ نوع واحد من المإ ًعضو ف تابع ٍ ٍ تصوّ ر أ ّننا نرٌد اآلن إنشاء. هذا الشًء مفٌ ٌد للغاٌة.* CPolygon شرات لٌطبع المساحة على الشاشة دون أن نع ّرف نوع الصفّ الذي ورث هذا التابع منCPolygon ًالصفّ األساس .ًالصفّ األساس // virtual members #include <iostream> using namespace std; class CPolygon { protected: int width, height; public: void set_values (int a, int b) { width=a; height=b; } virtual int area (void) =0; void printarea (void) { cout << this->area() << endl; } }; class CRectangle: public CPolygon { public: int area (void) { return (width * height); } }; class CTriangle: public CPolygon { public: int area (void) { return (width * height / 2); } };
264
20 10
{ )( int main ;CRectangle rect ;CTriangle trgl ;CPolygon * ppoly1 = &rect ;CPolygon * ppoly2 = &trgl ;)ppoly1->set_values (4,5 ;)ppoly2->set_values (4,5 ;)(ppoly1->printarea ;)(ppoly2->printarea ;return 0 }
تذكر :تشٌر الكلمة)المإ ّ شر( thisإلى الكابن الذي ٌت ّم تنفٌذه فً الذاكرة حالٌا.
إنّ الصفوف المجرّ دة و األعضاء virtualهً التً تمنح لغة C++خاصٌّة تعدد األشكال Polymorphism التً تع ّد إحدى أه ّم مبادئ البرمجة كابن ٌّة التوجّ ه .OOP بالطبع التطبٌقات التً أنشؤناها بسٌطة للغاٌة و لك ّنها فقط لتوضٌح هذه المبادئ و المٌزات ,و لكن تخٌل لو أكثر نفعا. أكثر إثارة و َ ط ّبقناها على مصفوفة من الكابنات بالطبع سٌكون األم ُر َ
265
الفصل التاسع شصر:
مالحظة :القوالب من المٌزات الحدٌثة التً ت ّم إنتاجها مع لغة ANSI-C++القٌاس ٌّة .لذلك إذا كنت تستعمل مترجما ا ال ٌدعم هذه اللغة القٌاس ٌّة فمن الممكن ّأال تكون قادراا على استخدامها.
تابع القوالب تسمح القوالب بإنشاء توابع عموم ٌّة تستطٌع أن تقبل أي نوع من البٌانات كوسطاء وتعٌد القٌمة المطلوبة من دون إعادة تحمٌل التابع أبدا .وهذه التوابع العمومٌة تخضع للقاعدة التالٌة: ; template < typename identifier > function_declaration : typenameهو نوع البٌانات الممرّ رة و قد ٌكون نوعا أساس ٌّا أو نوعا معرّ فا )مثل الصفوف(. : identifierاسم الوسٌط. مثال :هذا التابع ٌعٌد أكبر كابن من الكابنٌن الممررٌن إلٌه )من النوع)الصفّ ( .(GenericType > template < class GenericType { )GenericType GetMax (GenericType a, GenericType b ; ) return ( a > b ? a : b } كما ٌب ٌّن السطر األوّ ل فقد أنشؤنا قالبا لنوع )صفّ ( عا ّم من البٌانات دعوناه .GenericTypeلذلك فالتابع الذي تبل التصرٌح األوّ ل سٌؤخذ النوع المذكور GenericTypeكما اس ُتخ ِدم هذا النو ُع لتمرٌر وسٌطٌن منه إلى التابع )( GetMaxو الذي سٌعٌد أكبرهما. حتى اآلن لم ٌمثل النوع المعرف GenericTypeأي نوع منفصل من البٌانات ,ولكن عندما سٌستدعى التابع سنكون قادرٌن على استبدال هذا النوع بؤي نوع آخر والذي سندعوه نموذجا .patternللقٌام بذلك ٌمكننا أن نستدعً التابع العمومًّ بالطرٌقة التالٌة: ; )function <pattern> (parameters : patternنوع البٌانات الذي سٌتم استبدال النوع GenericTypeبه. فمثبل :الستدعاء هذا التابع لٌقارن بٌن عددٌن صحٌحٌن نكتب: ; int x,y ; )GetMax <int> (x,y واآلن س ٌُستدعى التابع )( GetMaxوكؤ ّنه أصبل من النوع .intلنكتب المثال بشكله النهابً:
266
6 10
// function template >#include <iostream ;using namespace std >template <class S { )S GetMax (S a, S b ;S result ;) return ( result = (a>b)? a : b } { )( int main ;int i=5, j=6, k ;float l=10.0, m=5.0, n ;)k=GetMax<int>(i,j ;)n=GetMax<float>(l,m ;cout << k << "\n" << n << endl ;return 0 }
فً هذه الحالة دعونا النوع العام باالسم Sبدال من االسم GenericTypeكما وٌمكننا أن نستخدم أي اسم آخر علما أنّ االسم Tهو األكثر شهرة مع القوالب )أل ّنه أوّ ل حرف من الكلمة .(template تستطٌع أن ترى كٌف استخدمنا التابع )( GetMaxمع نوعٌن مختلفٌن من البٌانات ( )int , floatمع أ ّننا لم نقم بإعادة تحمٌل التابع لٌستقبل أكثر من نوع. تستطٌع أن ترى أٌضا أ ّننا تمك ّنا من تعرٌف متغٌّر من النوع Sداخل التابع )(GetMax ;S result سٌت ّم استبدال المتغٌّر من النوع Sبآخر من النوع المذكور بٌن القوسٌن >< عند استدعاء التابع )(.GetMax مالحظة :فً هذه الحالة الوسطاء الممرّ رة إلى التابع هً من النوع Sوهو نفس نوع البٌانات التً سٌعٌدها التابع لذلك فإنّ المترجم ٌستطٌع أن ٌعرف نوع البٌانات من خبلل الوسطاء الممرّ رة مباشرة دون أن نذكره بٌن القوسٌن <> .كما ٌلً: ; int i, j ;) GetMax ( i , j 6 10
// function template >#include <iostream ;using namespace std >template <class S { )S GetMax (S a, S b ;S result ;))return (result = ((a>b)? a : b } { )( int main ;int i=5, j=6, k ;float l=10.0, m=5.0, n ;)k=GetMax(i,j ;)n=GetMax(l,m ;cout << k << "\n" << n << endl ;return 0 }
267
بٌنما ال ٌمكننا كتابة التعلٌمات التالٌة بسبب االختبلف بٌن األنواع الممرّ رة إلى التابع : ;int i ;long l ;)k = GetMax (i,l حٌث أنّ التابع ٌنتظر م ّنا أن نمرر إلٌه متغٌّرٌن )كابنٌن( من نفس النوع )الصفّ (. ٌمكننا أن نصنع تابعا عموم ٌّا ٌقبل أكثر من نوع من البٌانات كما فً المثال التالً : >template <class T, class U { )T GetMin (T a, U b ; ) return ( a < b ? a : b } فً هذه الحالة التابع )(ٌ GetMinقبل نوعٌن مختلفٌن من الوسطاء وٌعٌد كابنا من نوع الوسٌط األول ).(T نستطٌع استدعاء هذا التابع بؤحد الشكلٌن التالٌٌن : ; int i, j ;long l -0الشكل العام : ;)i = GetMin<int,long> (j,l -3الشكل المختصر : ;)i = GetMin (j,l
صف القوالب ّ
ٌمكننا أن نكتب ص ّفا لٌقبل أعضاء من أنواع عا ّمة ,و كمثال على ذلك:
>template <class T { class pair ;]T values [2 public: )pair (T first, T second { ;values[0]=first ;values[1]=second } ;} ّ ّ لنخزن قٌمتٌن صحٌحتٌن ٌخزن عنصرٌن من أي نوع مقبول ,فلو أردنا أن ننشؤ كابنا هذا الصفّ ٌستطٌع أن مثل 115و 36فعندها سنكتب: ;)pair<int> myobject (115, 36 و باستخدام نفس الصفّ السابق ٌمكننا أن ّ نخزن عنصرٌن من أي نوع آخر كاآلتً: ;)pair<float> myfloats (3.0, 2.18
268
// class templates #include <iostream> using namespace std; template <class T> class mypair { T a, b; public: mypair (T first, T second) {a=first; b=second;} T getmax (); }; template <class T> T mypair<T>::getmax () { T retval; retval = a>b? a : b; return retval; } int main () { mypair <int> myobject (100, 75); cout << myobject.getmax()<<endl; return 0; }
100
:template <class T> بالتعلٌمةgetmax() ال حظ كٌف سبقنا سطر تضمٌن )كتابة تعلٌمات( التابع template <class T> T pair<T>::getmax )( {…} أمّاtemplate<…> فوجب علٌنا أن نسبقه بالسابقةprototype ًوهذا أل ّننا استخدمنا التصرٌح المبدب . فبل داعً من ذكر هذه السابقة أمامهاinline ّاألعضاء المصرّ ح عنها كلٌّا داخل الصف
Template specialization تخصٌص القالب لنفترض,تسمح لنا هذه الخاص ٌّة بعمل مجموعة من األشٌاء مع نوع مع ٌّن دون األنواع األخرى من البٌانات لكن لن ٌقوم بهذه العملٌّة ّإال,عضو ٌعٌد باقً قسمة كابنٌن تابع ٍ ٍ أننا أردنا أن نكتب المثال السابق لٌحتوي على ّ إذا كان الكابنان من النوع الصحٌح :ً نستطٌع فعل ذلك كما ٌل.0 وإال سٌعٌد // Template specialization #include <iostream> using namespace std; template <class T> class mypair { T a, b; public: mypair (T first, T second) {a=first; b=second;} T module () {return 0;} }; template <> int mypair<int>::module() { return a%b; }
269
25 0
int main () { mypair <int> myints (100,75); mypair <float> myfloats (100.0,75.0); cout << myints.module() << '\n'; cout << myfloats.module() << '\n'; return 0; }
:كما ترى فإنّ شٌفرة التخصٌص من الشكل template <> class class_name <type> وال ٌمكننا أن نضعtemplate <> ٌعتبر التخصٌص جزءا من القالب لذلك علٌنا أن نبدأ التصرٌح بالكلمة النوع العام فً أول قوسٌن من الشكل >< وٌجب أن نبقٌهما فارغٌن وبعد اسم الصفّ علٌنا أن نضع النوع الذي .<> نرغب بتخصٌصه بٌن قوسٌن من نفس النوع
: بعض األشكال الممكنة للقوالب template <class T> template <class T, class U> template <class T, int N> template <class T = char> template <int Tfunc (int)>
26:
// The most usual: one class parameter. // Two class parameters. // A class and an integer. // With a default value. // A function as parameter.
الفصل العصرون :
تم ّكننا فضاءات األسماء من تجمٌع ع ّدة صفوف عا ّمة فً مجموعة واحدة ,من الكابنات و)أو( التوابع تحت اسم واحد لك ّل هذه المجموعة حٌث تصبح كلُّها أعضاء داخل المدى الذي ٌش ّكل فضاء االسم ,وٌكون ك ّل عضو منها قادرا على الوصول إلى األعضاء األخرى. الشكل الذي ٌمكننا من خبلله التصرٌح عن فضاء اسم جدٌد هو : namespace identifier { namespace-body } حٌث أنّ : :identifierهو أي اسم تختاره أنت شرٌطة أن ٌكون صحٌحا )ٌخضع لقواعد تسمٌة المتغٌّرات(. :namespace-bodyمجموعة من الصفوف و)أو( الكابنات و)أو( التوابع. مثال : namespace general { ;int a, b ;class S ;}…{()void B } و لكً نصل إلى أحد أعضاء فضاء االسم generalمن خارج الفضاء علٌنا أن نستخدم معامل المدى :: مثال: ;general::a ;)(general::B الوظٌفة التً ٌشغلها فضاء االسم مفٌدة خصوصا فً الحاالت التً ٌُح َتمل فٌها وجود أعضاء أو كابنات شاملة تمتلك نفس االسم داخل نفس البرنامج ما ٌعنً أنّ علٌنا أن نعٌد تسمٌتها لكً نستطٌع أن نتعامل معها كلّها ّإال أنّ فضاءات األسماء تق ّدم ّ حبل مناسبا لهذه المشكلة .راقب المثال التالً : 5 3.1416
// namespaces >#include <iostream ;using namespace std { namespace first ;int var = 5 } { namespace second ;double var = 3.1416 } { )( int main ;cout << first::var << endl ;cout << second::var << endl ;return 0 }
271
فً هذه الحالة لدٌنا متغٌّران شامبلن لهما نفس االسم varلكنّ األوّ ل موجو ٌد فً الفضاء firstأ ّما الثانً فهو موجو ٌد فً الفضاء secondلذلك لن ٌكون من الخطؤ وجود متغٌّرٌن لهما نفس االسم كما كان سٌحصل لو أزلنا الفضابٌن السابقٌن وأبقٌنا على المتغٌّرٌن فقط.
التعلٌمة using namespace تؤخذ هذه التعلٌمة الشكل التالً : ;using namespace identifier مثال : 3.1416 6.2832
// using namespace example >#include <iostream ;using namespace std namespace first { ;int var = 5 } namespace second { ;double var = 3.1416 } { )( int main ;using namespace second ;cout << var << endl ;cout << (var*2) << endl ;return 0 }
تستطٌع أن ترى كٌف أ ّننا لم نقم بكتابة اسم الفضاء الذي ٌنتمً إلٌه المتغٌّر varفً المرّ تٌن ,وذلك ألنّ التعلٌمة usingتقوم بتوجٌه المترجم كً ٌستخدم األعضاء الموجو ِدٌن فً فضاء االسم المذكور بعدها وبالتالً فإنّ المترجم ٌعلم اآلن أ ّنك تقصد المتغٌّر varالموجود فً الفضاء .second مالحظة :إنّ التعلٌمة using namespaceتخضع لقاعدة المدى المعروفة من قبل. حٌث أنّ مدى هذه التعلٌمة هو األقواس }{ التً كتبت فٌها .أ ّما إن ُك ِت َب ْ ت فً مكان التصرٌح عن المتغٌّرات الشاملة فإ ّنها ستكون ذات مدى شامل لك ّل البرنامج. مثال : 5 3.1416
// scope of // namespace first
// scope of // namespace second
// using namespace example >#include <iostream ;using namespace std namespace first } ;{ int var = 5 namespace second } ;{ double var = 3.1416 { )( int main { ;using namespace first ;cout << var << endl } { ;using namespace second ;cout << var << endl } } ;return 0
272
std الفضاء حٌث ت ّم تضمٌن كل صفوف. القٌاسٌة نفسهاC++ وهو مكتبة,واح ٌد من أفضل األمثلة حول فضاءات األسماء .std القٌاسٌة فً الفضاءC++ و كابنات وتوابع مكتبة : ِضبي // ANSI-C++ compliant hello world #include <iostream> using namespace std; int main () { std::cout << "Hello world in ANSI-C++\n"; return 0; }
Hello world in ANSI-C++
. رزّىٓ ِٓ اٌزؼبًِ ِغ أػؼبء ٘زا اٌفؼبءٟ ٌىٜغت أْ رغزخذَ اعُ اٌفؼبء ص ُّ ِؼبًِ اٌّذ٠ :مالحظة ُ ٌٕزّىٓ ِٓ العزغٕبء ػٓ روش اعusing namespace std ; ّخ١ٍّىٕٕب أْ ٔغزخذَ اٌزؼ٠ ّّٗٔئل أ : ٍٟ٠ ب ِغ أػؼبء ٘زا اٌفؼبء وّبٙ١ ِٓ أعً وً ِشّح عٕزؼبًِ فٜ ِؼبًِ اٌّذٚ اٌفؼبء // ANSI-C++ compliant hello world (II) #include <iostream> using namespace std;
Hello world in ANSI-C++
int main () { cout << "Hello world in ANSI-C++\n"; return 0; }
مارا تجذ؟ ما هى انسبب؟. ص ُّ ش ّغً اٌجشٔبِظusing namespace std ; ّخ١ًٍ اٌزؼ٠عشّة أْ رض
273
274
حلول التنارين غري احمللولة بنية الربنامج يف لغة الـ C++ .2 .3
)(main بفاصلة منقوطة ) ; ( تعلٌق. التعلٌق هو قطعة من الشٌفرة مهملة من قبل المترجم. إنهاء البرنامج بطرٌقة سلٌمة. القوسٌن }{ تضمٌن الملف المصدري > <iostreamالستخدام التعلٌمات الموجودة فٌه. ;"!cout<<"In the name of Allah. The peace upon you, Hello world
275
املتغيّرات .2أجب عن األسبلة التالٌة : ال ,ألنّ C++حسّاسة لحالة األحرف. نعم .ألن التصرٌح ٌوجب ذكر نوع المتغٌّر. ال. نعم. ٌ signed عنً أنّ المتغٌّر ذو إشارة سالبة أو موجبة ,بٌنما unsignedفالمتغٌّر ال ٌمكن أن ٌكون سالبا. .3امؤل الفراغات التالٌة : أماكن ,المإقتة ,اسم ٌ ,مٌزه ,الذاكرة. .4 (aخاطبة ألن المتغٌّر fال ٌقبل إشارة سالبة. (bخاطبة ألن اسم المتغٌّر ٌجب أال ٌبدأ برقم. (cخاطبة المتغٌّر dمن النوع العشري ولٌس محرفا. (dصحٌحة. (eخاطبة اسم المتغٌّر ٌجب أال ٌحوي نقطة أو رموز خاصة. (fصحٌحة. .5معظم هذه األخطاء منطقٌّة لذلك قد ٌعمل البرنامج مع وجود بعضها: نوع المتغٌّرٌن a, bعشري وتم اسنادهما لمتغٌّر من لنوع الصحٌح لذلك ٌجب تحوٌل نوع المتغٌّر resultإلى عشري ) سٌتجاهل األرقام العشرٌة بعد الفاصلة وٌخزن القسم الصحٌح فقط (. المتغٌّر resultال ٌقبل أرقاما سالبة فً حٌن أن القٌمة المسندة إلٌه سالبة فٌجب تعدٌله لٌكون .signed التعلٌمة ; result = A + bغٌر صحٌحة ألنه ال ٌوجد متغ ٌّر اسمه Aفٌجب أن نعدلها لتصبح ; .result = a + b التابع )( mainمن النوع intلذلك ٌجب أن ٌعٌد قٌمة من النوع الصحٌح إال أنه ال ٌمتك التعلٌمة; return 0فٌجب أن نضٌفها إلٌه ) ال ٌسبب خطؤ إال أنه ٌعطً تحذٌرا فقط (.
276
اإلدخال و اإلخراج .2 * ** *** **** ***** .3 #include <iostream> using namespace std; int main () { float f = 0.0 , c = 0.0 ; cout<<"Enter celecius degree: "; cin>>c; f = (9/5)*c + 32 ; cout<<'\n'<<f<<"\n"; return 0; } .4 #include <iostream> using namespace std; int main () { float f = 0.0; cout<<"Enter fehrnhite degree: "; cin>>f; float c = 5*(f - 32)/9 ; cout<<'\n'<< c <<"\n"; return 0; } .5 #include <iostream> using namespace std; int main () { float a = 0.0 , d = 0.0,v =0.0 ; int t = 0; cout<<"Enter accelration of body by m.s^-2: "; cin>>a; cout<<"Enter time of movement by seconds: "; cin>> t; d = 0.5*a*t*t; 277
v = a*t; cout<<"distance = "<<d<<" meters\n"; cout<<"velocity = "<<v<<" m.s^-1\n"; return 0; } .6 #include <iostream> using namespace std; int main () { float f = 0.0 , x =0.0; cout<<"Enter x: "; cin>>x; f = 5 - x*x; cout<<"\nf("<<x<<") = "<<f<<endl; return 0; } .7 #include <iostream> using namespace std; int main () { int n = 0; cout<<"Enter n: "; cin>>n; cout<<"\nsum of numbers from (1 to "<<n<<") = "<<n*(n+1)/2<<endl; cout<<"\navg = "<<(float)(n*(n+1)/2)/n<<endl;//avg = sum / n return 0; } .8 #include <iostream> using namespace std; int main () { cout<<"Just remember \"Allah created You\'.\n"; return 0; }
278
.9 #include <iostream> using namespace std; int main () { int x1,x2,x3; cout<<"Enter three numbers plz: "; cin>>x1>>x2>>x3; cout<<"\nAverage of ["<<x1<<','<<x2<<','<<x3<<"] = " << float(x1+x2+x3)/3<<endl; return 0; }
279
املعامالت .2 int x = 0, a = 0, b = 1, d = 3, c = 2; bool e = true , r = true, t = false; العبارة a += (b = c = d - 5) ; d %= 2 * c / ++b ; a = d - (b += (c * (1-a))); e = !e r = e || t t = e && r e = !( (e && r ) || (e && t ) ) ;
الجواب -2 3 0 0 0 0 1 .3
العبارة x=7+3*6/2-1; x = 2 % 2 + 2 * 2 -2 / 2 ; x=(3*9*(3+(9*3/(3)))); c = 2*b - 3/d + a++;
الجواب 15 3 324 1 .4
cout<< cout<< cout<< cout<<
27:
++a ; a++ ; a++ / 2 ; ++a / 2 ;
1 0 0 0
بنى التخكه .2 #include<iostream > using namespace std; float avg =0; int main() { cout<<"Enter Average: "; cin>>avg; if(avg > 89 && avg <= 100 ) cout<<"Excellent!\n"; else if(avg > 79 && avg <= 89) cout<<"Very Good\n"; else if(avg > 69 && avg <= 79) cout<<"Good\n"; else if(avg > 59 && avg <= 69) cout<<"Passed\n"; else cout<<"Not passed\n"; return 0; } .3 البرنامج while ( c <= 5 { product *= c; ++c; if ( gender == cout<< "Woman" else; cout<<"man"; while ( z >= 0 sum += z;
)
التصحٌح while ( c <= 5 ) { product *= c; ++c;
} 1 ) ;
)
if ( gender == 1 ) cout<< "Woman" ; else // ال ٌوجد فاصلة منقوطة هنا cout<<"man"; while ( z >= 0 ) { sum += z;
z--; } // nested loop #include <iostream> using namespace std; int main () { int j = 1; for( int i = 1 ; i<=3 ; i++) while( j<i ) { cout <<"* " ; j++; } return 0; }
281
// nested loop #include <iostream> using namespace std; int main () { int j = 1; for( int i = 1 ; i<=5 ; i++) {while( j<=i ) {cout <<"* " ; j++; } cout<<endl; j = 1;} return 0; }
.4 #include <iostream> using namespace std; int main () { int x,y,z,max,med,min; cout<<"Enter three numbers: "; cin>>x>>y>>z; if (x > y && x > z && y > z) cout<<z<<"\t"<<y<<"\t"<<x<<endl; else if (x > y && x > z && z>y ) cout<<y<<"\t"<<z<<"\t"<<x<<endl; if (y > x && y > z && x > z) cout<<z<<"\t"<<x<<"\t"<<y<<endl; else if (y > x && y > z && z>x ) cout<<x<<"\t"<<z<<"\t"<<y<<endl; if (z > y && z > x && y > x) cout<<x<<"\t"<<y<<"\t"<<z<<endl; else if (z > y && z > x && x>y ) cout<<y<<"\t"<<x<<"\t"<<z<<endl; return 0; } .5 البرنامج #include <iostream> using namespace std; int main () { for(int i = 3;i<=6;i++) { for(int j = i;j<i+4;j++) cout<<j<<" "; cout<<"\n"; } return 0; } #include <iostream> using namespace std; int main () { for(int i = 0;i<=3;i++) { for(int j = 0;j<=3;j++) if(i>=j) cout<<j+3+i<<" "; cout<<"\n"; } return 0; }
282
الشكل 3 4 5 6
4 5 6 7
5 6 7 8
6 7 8 9
3 4 5 5 6 7 6 7 8 9
#include <iostream> using namespace std; int main () { for(int i = 0;i<=3;i++) { for(int j = 0;j<=3;j++) if(i<=j) cout<<j+3+i<<" "; else cout<<" "; // 2 spaces cout<<"\n"; } return 0; } #include <iostream> using namespace std; int main () { for(int i = 0;i<=3;i++) { for(int j = 0;j<=3;j++) if(i+j>=4-1) cout<<j+3+i<<" "; else cout<<" ";//2 spaces cout<<"\n"; } return 0; } #include <iostream> using namespace std; int main () { for(int i = 0;i<=3;i++) { for(int j = 0;j<=3;j++) if(i<=j) cout<<j+3<<" "; cout<<"\n"; } return 0; } #include <iostream> using namespace std; int main () { for(int i = 0;i<=3;i++) { for(int j = 0;j<=3;j++) if(i == 0 || i == 3) cout<<j+3+i<<" ";//2 spaces else { 283
3 4 5 6 5 6 7 7 8 9
6 6 7 6 7 8 6 7 8 9
3 4 5 6 4 5 6 5 6 6
3 4 5 4 5 6 7 8
6 7 8 9
if(j == 0 || j == 3) cout<<j+3+i<<" "; else cout<<" ";// 2 spaces } cout<<"\n"; } return 0; } .6 #include <iostream> using namespace std; int main () { cout<<"Enter n: "; int n; cin>>n; if(n%10 == 0) cout << "yes\n"; else cout<<"no\n"; return 0; } .7 #include <iostream> #include<cmath > using namespace std; int main () { double x, fx =0.0 ; err: cout<<"Enter x ecept (1 or 3): "; cin>>x; if(x == 1 || x == 3) {cout << "Infinite Error You can't Enter 1 or 3\n"; goto err;} else{ fx = (pow(x,3) - 7)/(pow(x,2)-4*x+3); cout<<"f("<<x<<") = "<<fx<<endl; } return 0; }
284
.8 #include <iostream> using namespace std; int main() { int i,sum=0; for(i=1;i<=99;i++) if(i%2==0 && i%3==0) sum+=i; cout<<"sum="<<sum<<endl; return 0; }
.9 #include<iostream> using namespace std; void main() { int a,b,lcm ; cout << "enter a and b" << endl; cin>>a>>b; if (a == 0 || b == 0) lcm = 0; else if ( a>b && a%b==0 ) cout <<"lcm="<<a<<endl ; else if(b>a && b%a==0) cout <<"lcm="<<b<<endl; else lcm=a*b; cout <<"lcm="<<lcm<<endl; } .: #include<iostream > using namespace std; void main() { double x,p=1.0,y; cout <<"Enter x, y: "; cin >> x >> y; if(y>=0){ for(int i = 1; i<=y;i++) p *=x; cout<< p << endl; } }
285
#include<iostream > using namespace std; void main() { double x,p=1.0,y; cout<<"Enter x, y: "; cin>>x>>y; if(y>=0){ int i = 1; while( i<=y ) { p *=x; i++; } cout<< p << endl; } }
.21 #include<iostream > using namespace std; void main() { int n; char c; cout<<"Enter charactor then number: "; cin >> c >> n; for(int i = 0; i<n;i++){ for(int j = 0; j<n;j++) if(i>=j) cout<<c<<" "; cout<<endl;} } .22 #include<iostream.h> void main() { float x,y; char c = 'n'; while(c == 'n' ) { cout<<"Enter two numbers: "; cin>> x >> y; ZeroErr: if(y != 0) { cout<< x/y << endl; } else { cout<<"Error You can't enter 0"; cout<<"ReEnter second number without 0 plz: "; cin>> y; goto ZeroErr; } inputErr: cout<<"press n for new operation,(e to exit): "; cin>> c; if(c == 'n' || c == 'N') continue; else if(c == 'e' || c == 'E') break; else goto inputErr; } } .23 #include<iostream > using namespace std; void main() 286
{ int x; cout<<"Enter x: "; cin>>x; int i = 1; while(i<=x) { if(x%i == 0)cout<<i<<endl; i++; } }
التوابع .0 التابع int Sum(int a , int b) { int sum = a + b; } int divide(int a , int b) { return (float)a/b; } void subtract(int a , int b) { return a-b; }
األخطاء وٌجب أن ٌعٌد قٌمة إال أنه الint هذ التابع من النوع return statement; ٌحتوي على التعلٌمة return sum; // return a+b; و هو ٌعٌد قٌمة من النوعint هذا التابع من النوع .float فعلٌنا أن نغٌر نوع التابع إلىfloat float divide(int a, int b({…} وٌجب ّأال ٌعٌد قٌمة لكنهvoid هذ التابع من النوع لذلك سنغٌرreturn a-b; ٌحتوي على التعلٌمة int نوعه إلى int subtract)int a, int b({…} .3
البرنامج #include<iostream>
using namespace std; int x = 0; float b; float d(float a , float& b) { a--; b++; x = a/b; return (x+1)/2.0; } int main() { float a; cout<<"x\tb\ta\n"; cout<<x<<"\t"<<b<<"\t"<<a<<endl; a = b = ++x; cout<<d(a , b)<<endl; cout<<x<<"\t"<<b<<"\t"<<a<<endl; return 0; }
الناتج x b 0 0 0.5 0 2 x b 0 0 0.5 1 2
a -1.07374e+008 1 : أ ّما بعد التعدٌل a -1.07374e+008 1
هً قٌمة-1.07374e+008 القٌمة:مالحظة عشوابٌة تختلف دوما وهً عشوابٌة ألن المتغٌّر متغٌّر موضعً ولقد قلنا إنّ المتغٌّراتa الموضعٌة تؤخذ قٌما عشوابٌة إذا لم تت ّم تبدبتها أ ّما المتغٌّرات الشاملة فهً تؤخذ القٌم الصفرٌة للنوع
.2 287
#include<iostream> using namespace std; float sum(float a,float b); float sub(float a,float b); float mult(float a,float b); float divide(float a,float b); void main() { float x,y; char op ; cout<<"Enter x: "; cin>>x; cout<<"Enter operator from{+,-,*,/}: "; cin>>op; cout<<"Enter y: "; cin>>y; switch(op) { case '+': cout<<sum(x,y)<<endl; break; case '-': cout<<sub(x,y)<<endl; break; case '*': cout<<mult(x,y)<<endl; break; case '/': if(y!=0) cout<<divide(x,y); else cout<<"Error divide by 0\n"; break; } } float sum(float a,float b) { return a+b; } float sub(float a,float b) { return a-b; } float mult(float a,float b) { return a*b; } float divide(float a,float b) { return a/b; }
.1 #include<iostream > using namespace std; float rec_power(float a,int b); float frec_power(float a,int b); 288
void main() { float x; int y; cout<<"Enter x, y: "; cin>>x>>y; cout<<"Recutrivity power = "<<rec_power(x,y)<<endl; cout<<"Frecuently power = "<<frec_power(x,y)<<endl; } float rec_power(float a,int b) { if(b == 0) return 1; else if(b>0) return a*rec_power(a,b-1); else return 1/(a*rec_power(a,-b-1)); } float frec_power(float a,int b) { float res = 1; if(b==0) res = 1; else if(b>0) for(int i=1;i<=b;i++) res*=a; else{ for(int i=1;i<=-b;i++) res*=a; res = 1/res; } return res; } .5 #include<iostream > using namespace std; float frec_power(float a,int b); float pi(long n); void main() { long n ; cout<< "enter n: "; cin>>n; cout<<"\n"<<pi(n)<<endl; } float pi(long n) { float p = 0; for(long i = 0;i<n;i++) 289
p += 4*frec_power(-1,i)/(2*i+1); return p; } float frec_power(float a,int b) { float res = 1; if(b==0) res = 1; else if(b>0) for(int i=1;i<=b;i++) res*=a; else { for(int i=1;i<=-b;i++) res*=a; res = 1/res; } return res; } .6 #include<iostream > using namespace std; int frec_gcd(int a, int b); // frecuently int rec_gcd(int x, int y); // recursivity void main() { int a , b; cout<<"Enter a , b: "; cin>>a>>b; cout<<"\nfrequently result: "<< frec_gcd(a,b); cout<<"\nrecursivity result: "<< rec_gcd(a,b)<< endl; } int frec_gcd(int a, int b) { while(a != b) { if(a>b) a-=b; else b-=a; } return a; // or return b : a = b } int rec_gcd(int x, int y) { if(x == y) return x; else if (x>y) return rec_gcd(y,x-y); 28:
else return rec_gcd(x,y-x); //second way to finding gcd /*if(y == 0) return x; else return rec_gcd(y,x%y); */ }
.7 #include<iostream > #include<math.h> using namespace std; long fact(int a); double Compination(int n, int k); double Permitation(int n, int r); void main() { int n , k , r ; cout<<"Enter n: "; cin>>n; cout<<"\n"<<n<<"! = "<<fact(n); cout<<"\nEnter k < " << n << " : "; cin>>k; cout<<"\nc("<<n<<","<<k<<") = "<<Compination(n,k); cout<<"\nEnter r < " << n << " : "; cin>>r; cout<<"\np("<<n<<","<<r<<") = "<<Permitation(n,r)<<endl; } long fact(int a) { long f = 1; for(int i =1; i<=a ; i++) f*= i; return f; } double Compination(int n, int k) { double c = fact(n)/(fact(n-k)*fact(k)); return c; } double Permitation(int n, int r) { double p =Compination(n,r)*fact(r); return p; 291
} .8 #include<iostream > using namespace std; void multiple(int a, int b); bool multiple1(int a, int b); void main() { int n , k ; cout<<"Enter n, k: "; cin>>n>>k; if(multiple1(n,k)) cout<<"true\n"; else cout<<"false\n"; multiple(n,k); } void multiple(int a, int b) { if(b>a && b%a ==0) cout<<"true\n"; else cout<<"false\n"; } bool multiple1(int a, int b) { if(b>a && b%a ==0) return true; return false; // no need to else statement. why? } .9 #include<iostream > using namespace std; void print_primes(int a); bool is_prime(int a); void main() { int n; cout<<"Enter n: "; cin>>n; if(is_prime(n)) cout<<"true\n"; else cout<<"false\n"; print_primes(n); } bool is_prime(int a) { 292
if(a>0 && a != 1)//positive and not 1 (1 isn't prime) { int sum = 0; for(int i = 1; i <= a ; i++) { if(a%i == 0) sum++; } if(sum == 2) return true; } return false; } void print_primes(int a) { for(int i = 1; i <= a ; i++) if(is_prime(i)) cout<<i<<"\n"; } .01 #include<iostream> using namespace std; double abs_val(double x) { if(x>0) return x; else return -x; } void main() { double n; cout<<"Enter n: "; cin>>n; cout<<"| "<<n<<" | = "<<abs_val(n)<<endl; } .00 #include<iostream> using namespace std; const double pi = 3.141592; double Circl_space(double r) { return (pi*r*r); } double Rect_space(double a , double b) { return (a*b); } double Trgl_space(double b , double h) { return (0.5*b*h); } void main() { cout<<"1- Calculate circle spsace\n"; 293
cout<<"2- Calculate rectangle spsace\n"; cout<<"3- Calculate triangle spsace"; cout<<"\nEnter number from list above to select: "; int ch ; cin>>ch; cout<<"\n"; switch(ch) { case 1 : cout<<"Calculating circle space.. .\n"; double r ; cout<<"Enter r: "; cin>>r; cout<<"S ="<<Circl_space(r)<<endl; break; case 2 : cout<<"Calculating rectangle space.. .\n"; double a, b ; cout<<"Enter width: "; cin>>a; cout<<"Enter height: "; cin>>b; cout<<"S ="<<Rect_space(a,b)<<endl; break; case 3 : cout<<"Calculating triangle space.. .\n"; double h; cout<<"Enter base: "; cin>>b; cout<<"Enter height: "; cin>>h; cout<<"S ="<< Trgl_space(b,h)<<endl; break; default: cout<<"program will terminate now!."; break; } } .12
#include<iostream> using namespace std; int print(int h); int main() { int h;//h is hieght cin>>h; print(h); return 0; } int print(int h) { int i,j,k; 294
for(i=1;i<=h;i++)//number of rows { for(j=1;j<=h-i;j++)//from line beginning to the first star pos print space cout<<" ";// 2 spaces for(k=1;k<=2*i-1 ;k++)// from last space in line to (2*line number -1) cout<<"* "; // print * where (2*line number -1) is number of // * in each line (i) cout<<"\n"; // print new line } return 0; }
295
املصفوفات -2 for ( int i = 0; i<= 10; i++ ) (a i<10 غٌر موجود إذا ٌجب أن ٌكون شرط التوقفb[10] والعنصر21 سٌؤخذ العداد القٌمة int i = 1 أي2 القٌمةi ًأو ٌمكن أن نعط cout<<a[1]<<" "<<a[2]<<" "<<a[3]<<endl; (b .a[2] وa[1] وa[0] ً ألن عناصرها هa غٌر موجود فً المصفوفةa[3] العنصر double f[ 3 ] = { 1.1, 10.01, 100.001, 1000.0001 }; )c عناصر فقط لذلك ٌجب حذف أحد العناصر على األقل4 تتسع لـf المصفوفة d[ 1, 9 ] = 2.345; )d d[ 1][9] = 2.345; ٌجب أن ٌكون كل دلٌل ضمن قوسٌن أي -3 .p[3] وp[2] وp[1] وp[0] .تعرٌف .d[2][4] .20
(a (b (c (d -4
const int arraySize = 10; (a double fractions[ arraySize ] = { 0.0 }; )b fractions[ 8 ] = 1.667; fractions[ 6 ] = 3.333; (c (d for(int i=0; i<arraySize;i++) cout<<"fractions["<<i<<"]="<<fractions[i]<<endl; -5 #include<iostream> using namespace std; const int n=8; void print(int a[]) { for(int i=0;i<n;i++) cout<<a[i]<<" "; } int main() { int A[n]={1,5,4,3,7,2,9,0},i,j,temp; for(i=0;i<n;i++)//ascending for(j=0;j<n-1;j++) if(A[j]>A[j+1]) {temp=A[j];A[j]=A[j+1];A[j+1]=temp;} cout<<"ascending: "; print(A);
296
for(i=0;i<n;i++)//descending for(j=0;j<n-1;j++) if(A[j]<A[j+1]) {temp=A[j];A[j]=A[j+1];A[j+1]=temp;} cout<<"\ndescending: "; print(A); cout<<endl; return 0; }
-6 #include<iostream> using namespace std; const int n=10; int a[n],b[n],c[2*n],i,j; void read(int arr[]) { for(i=0;i<n;i++) cin>>arr[i]; } void merge(int a[],int b[]) { for(i=0;i<n;i++) { c[i]=a[i]; c[i+n]=b[i]; } } void print(int arr[]) { for(int i=0;i<2*n;i++) cout<<a[i]<<" "; } int main() { cout<<"enter A members:\n"; read(a); cout<<"enter B members:\n"; read(b); merge(a,b); cout<<"C=[ "; print(c); cout<<"]\n"; return 0; }
-7 #include<iostream> using namespace std; const int n=10; int main() { int a[n],frq[4]={0},i; cout<<"enter array of 10 integers:\n"; for(i=0;i<n;i++)
297
cin>>a[i]; for(i=0;i<n-1;i++) { if(a[i]<a[i+1]) frq[0]++; else if(a[i]>a[i+1]) frq[1]++; else if(a[i]==a[i+1]) frq[2]++; else frq[3]++; } if(frq[0]==9) cout<<"the array else if(frq[1]==9) cout<<"the array else if(frq[2]==9) cout<<"the array else cout<<"the array return 0;
is growing.\n"; is decreasing.\n"; is constant.\n"; is growing and decreasing.\n";
}
-8 #include<iostream> #include<string> using namespace std; int main() { int n,mark[100],i,j,temp; string name[100],strTemp; cout<<"enter students number "; cin>>n; for(i=0;i<n;i++) { cout<<"student "<<i+1<<" name:"; cin>>name[i]; cout<<"student "<<i+1<<" mark:"; cin>>mark[i]; } for(i=0;i<n;i++) for(j=0;j<n-1;j++) if(mark[j]<mark[j+1]) { temp=mark[j];mark[j]=mark[j+1];mark[j+1]=temp; strTemp=name[j];name[j]=name[j+1];name[j+1]=strTemp; } cout<<"students ranks by marks:\n"; for(i=0;i<n;i++) cout<<name[i]<<endl; return 0; }
298
-9 // program to add matrix to another one //using functions #include <iostream> using namespace std; #define MAX 10 int a[MAX][MAX],b[MAX][MAX],c[MAX][MAX]; void add(int [][MAX],int [][MAX],int [][MAX],int ,int ); void print(int [][MAX],int,int); int main() { int m,n; cout<<"number of rows=";cin>>m; cout<<"number of columns=";cin>>n; add(a,b,c,m,n); print(a,m,n); cout<<"\n +\n\n"; print(b,m,n); cout<<"\n =\n\n"; print(c,m,n); return 0; } void print(int arr[][MAX],int m,int n) { int i,j; for(i=0;i<m;i++) { for(j=0;j<n;j++) cout<<arr[i][j]<<" "; cout<<"\n"; } } void add(int a[][MAX],int b[][MAX],int c[][MAX],int m,int n) { int i,j; for(i=0;i<m;i++) for(j=0;j<n;j++) { cout<<"a["<<i+1<<"]["<<j+1<<"]=";cin>>a[i][j]; cout<<"b["<<i+1<<"]["<<j+1<<"]=";cin>>b[i][j]; c[i][j]=a[i][j]+b[i][j]; } }
-: #include<iostream> #include<string> #include<cstdlib> #include<ctime> using namespace std;
299
int main() { cout<<"enter your Choice :\n"; cout<<"R\tfor Rock\n"; cout<<"P\tfor Paper\n"; cout<<"S\tfor Scissors\n"; cout<<"The computer chose\n"; int cmpCounter = 0; int YourCounter = 0; lbb: cout<<"\nYour points:\t\t" << YourCounter; cout<<"\nComputer points:\t" << cmpCounter; string mesg ; srand(time(0));//seed rand int r = rand() % 3 ; switch (r) { case 0: mesg = "Computer choice's Rock"; break; case 1: mesg = "Computer choice's Paper"; break; case 2: mesg = "Computer choice's Scissors"; break; } cout<<"\nChose please:"; string PlayerChosen ; cin>>PlayerChosen ; if (PlayerChosen == "R" || PlayerChosen == "r") { cout<<mesg; switch (r) { case 0: cout<<"\nNo Winner"; cmpCounter = cmpCounter; YourCounter = YourCounter; goto lbb; break; case 1: cout<<"\nComputer Won..."; cmpCounter+=1; goto lbb; break; case 2: cout<<"\nYou Won..."; YourCounter+=1; goto lbb; 29:
break; } } else if (PlayerChosen == "P" || PlayerChosen == "p") { cout<<mesg; switch (r) { case 0: cout<<"\nYou Won..."; YourCounter+=1; goto lbb; break; case 1: cout<<"\nNo Winner"; cmpCounter = cmpCounter; YourCounter = YourCounter; goto lbb; break; case 2: cout<<"\nComputer Won..."; cmpCounter+=1; goto lbb; break; } } else if (PlayerChosen == "S" || PlayerChosen == "s") { cout<<mesg; switch (r) { case 0: cout<<"\nComputer Won..."; cmpCounter+=1; goto lbb; break; case 1: cout<<"\nYou Winner"; YourCounter+=1; goto lbb; break; case 2: cout<<"\nNo Winner..."; cmpCounter = cmpCounter; YourCounter = YourCounter; goto lbb; break; } } else if (PlayerChosen == "E" || PlayerChosen == "e") { 2:1
cout<<"Do you want to exit the game? (y/n)"; string anser; cin>>anser; if (anser == "Y" || anser == "y") return 0;//exit main func else goto lbb; } else { cout<<"\nBe sure from your inserting..."; goto lbb; } return 0; }
2:2
الربدلة كائنية التوجه .2 #include<iostream> using namespace std; const double pi = 3.141592; class Circle { private : double radius; public: void set_radius(double r); double calc_space(); double calc_perimeter(); }; void Circle::set_radius(double r) { radius = r; } double Circle::calc_space() { return pi*radius*radius; } double Circle::calc_perimeter() { return 2*pi*radius; } void main() { Circle c1; double r; cout<<"Enter radius: "; cin>>r; c1.set_radius(r); cout<<"c1 Space = "<<c1.calc_space()<<endl; cout<<"c1 perimeter = "<<c1.calc_perimeter()<<endl; } .3 #include<iostream> #include<math.h> using namespace std; class Point { public: double x, y; void set_point(double p_x, double p_y); double distance(Point p1, Point p2); }; 2:3
void Point::set_point(double p_x, double p_y) { x = p_x; y = p_y; } double Point::distance(Point p1, Point p2) { return( sqrt( pow( (p2.x-p1.x),2) + (pow((p2.y-p1.y),2) ) ) ); } void main() { Point p1,p2; double x1,y1,x2,y2; cout<<"Enter x1, y1: "; cin>>x1>>y1; cout<<"Enter x2, y2: "; cin>>x2>>y2; p1.set_point(x1,y1); p2.set_point(x2,y2); cout<<"Distance between p1 and p2 is :" <<p1.distance(p1,p2)<<endl; } .4 #include<iostream> using namespace std; const double pi = 3.141592; class Circle { private : double radius; public: Circle(){} Circle(double r){radius =r;} void set_radius(double r); double calc_space(); double calc_perimeter(); }; void Circle::set_radius(double r) { radius = r; } double Circle::calc_space() { return pi*radius*radius; } double Circle::calc_perimeter() { return 2*pi*radius; } void main() 2:4
{ Circle c1; double r; cout<<"Enter radius: "; cin>>r; Circle c2(r); c1.set_radius(r); cout<<"c1 Space\t"<<"c2 Space\t"<<"c1 perimeter\t"<<"c2 perimeter\n"; cout<<c1.calc_space()<<"\t\t"<<c2.calc_space() <<"\t\t"<<c1.calc_perimeter()<<"\t\t"<<c2.calc_perimeter()<<endl; } . لٌست صحٌحة أل ّننا لم نضف المشٌد العاديCircle circle; العبارة
#include<iostream> #include<math.h> using namespace std; class Point { public: double x, y; Point(){} Point(double p_x, double p_y) { x = p_x ; y = p_y ; } void set_point(double p_x, double p_y); double distance(Point p); }; void Point::set_point(double p_x, double p_y) { x = p_x; y = p_y; } double Point::distance(Point p) { return sqrt( pow( (p.x-this->x),2) + (pow((p.y-this->y),2) ) ); } int main() { Point p1,p2; p1.set_point(1,2); p2.set_point(2,1); cout<<p1.distance(p2)<<endl; return 0; }
2:5
.5 .6
.7 #include<iostream.h> class Printing {public: Printing(){ cout<< "Give the world the best you have, and the best will come to you.\n"; } ~Printing(){ cout<< "\nIf man hasn't discovered that he will die for, he isn't fit to live.\n"; } }print_that; int main() { cout<<"Sweat plus sacrifice equals success."; return 0; } ( قد ال ٌعمل البرنامجusing namespace std; )ال تستخدم#include<iostream.h> ال تغ ٌّر التعلٌمة:مالحظة ( بشكل كامل ) قد ال ٌطبع العبارة الثالثة الموجودة فً الهادم .8 #include<iostream> #include<math.h> using namespace std; class Point { public: double x, y; void set_point(double p_x, double p_y); double distance(Point p1, Point p2); Point operator+ (Point p); }; void Point::set_point(double p_x, double p_y) { x = p_x; y = p_y; } double Point::distance(Point p1, Point p2) { return sqrt( pow( (p2.x-p1.x),2) + (pow((p2.y-p1.y),2) ) ); } Point Point::operator+(Point p) { Point temp; temp.x = this->x + p.x; temp.y = this->y + p.y; return temp; } void main() { Point p1,p2; 2:6
double x1,y1,x2,y2; cout<<"Enter x1, y1: "; cin>>x1>>y1; cout<<"Enter x2, y2: "; cin>>x2>>y2; p1.set_point(x1,y1); p2.set_point(x2,y2); cout<<"Distance between p1 and p2 is : "<<p1.distance(p1,p2)<<endl; cout<<"c(x,y) = ("<<(p1+p2).x<<", "<<(p1+p2).y<<")\n"; } .9 .getIncrementedData من أمام التصرٌح عن التابعconst أزل الكلمة . لذلك علٌك أن تزٌل التعلٌمة الخاصة بالطباعة منهstatic من النوعgetcount التابع
2:7
اخلامتة كل ما عليك أن تتعلّمو في البرمجة ,وليس ىذا ىو آخر الكتب التي ألفت أخيراً ال يحوي ىذا الكتاب على ّ
في ىذا المجال؛ لذلك إن كنت ترى أ ّن البرمجة ىي الشي الذي كنت تبحث عنو فعليك أن تبحث عن كتاب آخر لتكمل معو رحلتك.
هم اجعلو في ميّان حسناتنا وال تحرمنا أجره. اللّ ّ هم من كان سبباً في إنجاز ىذا الكتاب فحرمو على النار وارزقو الجنّة برحمتك يا أرحم الراحمين. اللّ ّ هم ما كان من صواب فمنك وحدك ال شريك لك ,وما كان من زلل أو نسيان فمن أنفسنا والشيطان. اللّ ّ محمد وعلى آلو وصحبو أجمعين. وصلّى اهلل على سي ّدنا ّ رب العالمين. وآخر دعوانا أن الحمد هلل ّ ***
ٌرجى زٌارة الرابط التالً إلبداء رأٌكم بالكتاب https://docs.google.com/spreadsheet/viewform?formkey=dDVxYmV5UFgwaHBFZkQ0U3RiO TNNSUE6MQ&ifq
2:8
املراجع 1- The cplusplus.com tutorial ) http://www.cplusplus.com/doc/ ( Author: Juan Soulie 2- C++ How to Program Fifth Edition 3- The C+ + Programming Language Third Edition, Author: Bjarne Stroustrup(the creator of c++) 4- Java How to Program C# And VB.net 8002 ٛ٠دٛاي عزٛغ١ح ِغ فٛح ثخطٛ خط-5 فخ١ٍأؽّذ عّبي خ
2:9