Professional Documents
Culture Documents
الـمحتويات
Contents
Expressions التعبيـــــــــــرات
Statements الجمــــــــــل
Functions الـــــــــــدوال
Classes الفئــــــــــات
توفر كل لغة برمجة مستخدمة على نطاق واسع مجموعة مشرتكة من املزيات ،
تختلف تفاصيلها من لغة إلى أخرى. •
إن فهم تفاصيل كيفية توفري اللغة لهذه املزيات هي أول خطوة نحو فهم اللغة. •
من بني أهم تلك السمات املشرتكة أنواع مدمجة مثل األعداد الصحيحة واألحرف وما إلى ذلك ، •
متغريات ،تتيح لنا منح أسماء لكائنات نستخدمها ، •
تعبريات وجمل تعالج قيم هذه األنواع ، •
بنية تحكم ،مثل إذا_ ifأو طالـما_ ،whileتسمح لنا بتنفيذ مجموعة إجراءات بشكل متكرر أو مرشوط •
دوال تسمح لنا بتعريف وحدات حوسبة قابلة لالستدعاء •
قد تكون الفئات أهم مزية في يس ، ++واليت تتيح للمربمجني تعريف أنواعهم الخاصة. •
في يس ، ++يطلق على هذه األنواع أحيا ًنا "أنواع الفئات" لتميزيها عن األنواع املدمجة في اللغة. •
تسمح بعض اللغات للمربمجني بتعريف أنواع تحدد فقط بيانات يتكون منها النوع. •
تسمح بعضها اآلخر ،مثل يس ، ++للمربمجني تعريف أنواع تتضمن العمليات وكذلك البيانات. •
يتمثل أحد أهداف التصميم الرئيسية لـ يس، ++ •
في السماح للمربمجني بتعريف أنواعهم الخاصة اليت يسهل استخدامها مثل األنواع املدمجة. •
تستخدم مكتبة اليس ++القياسية هذه املزيات لتنفيذ مكتبة غنية ألنواع الفئات والدوال املرتبطة بها. •
أول خطوة في إتقان يس ++هي مواضيع الجزء األول -تعلم أساسيات اللغة واملكتبة .-
حيث يغطي الفصل الثاني األنواع املدمجة وينظر بإيجاز في آليات تعريف أنواعنا الجديدة. •
يقدم الفصل الثالث نوعني من أنواع املكتبات األساسية :السلسلة stringواملتجه .vector •
أيضا املصفوفات ،array
يغطي ذلك الفصل ً •
وهي بنية بيانات منخفضة املستوى مدمجة في يس ++وعدة لغات أخرى. •
تغطي الفصول من الرابع إلى السادس التعبريات والجمل والدوال. •
يختتم هذا الجزء بالفصل السابع ،الذي يصف أساسيات بناء أنواع فئاتنا. •
كما سرنى ،فإن تعريف أنواعنا الخاصة يجمع كل ما تعلمناه من قبل ، •
وذلك ألن كتابة فئة ما يستلزم استخدام األقسام املشمولة في الجزء األول. •
الفصــــــــــل . 2املتغيــــــــــرات واﻷنــــــــــواع اﻷساسيــــــــــة
الـمحتويات
Contents
األنواع أساسية ألي برنامج :فهي تخربنا بما تعنيه بياناتنا والعمليات اليت يمكننا إجراؤها على تلك البيانات.
كذلك توفر اللغة آليات تتيح لنا تعريف أنواع بيانات خاصة بنا.
تستخدم املكتبة هذه اآلليات لتعريف أنواع أكرث تعقي ًدا ، •
مثل سالسل األحرف متغرية الطول واملتجهات وما إلى ذلك. •
يغطي هذا الفصل األنواع املدمجة built-inوهو بداية تغطيتنا لكيفية دعم يس ++ألنواع أكرث تعقي ًدا.
تعرف األنواع معىن البيانات والعمليات في برامجنا .فمعىن جملة بسيطة مثل
;i = i + j
تعتمد على نوعي iو .j
إذا كانت iو jأعدا ًدا صحيحة ، integersفإن هذه الجملة لها معىن حسابي عادي وهو الجمع. •
أما إذا كانت iو jعبارة عن كائنات عنرص_مبيعات ،فإن هذه الجملة تجمع مكونات هذين العنرصين. •
. 2٫1اﻷنــــــــــواع الـمدمجــــــــــة اﻷوليــــــــــة
2٫1٫1اﻷنواع الحسابية
2.1.1. Arithmetic Types
يختلف حجم األنواع الحسابية -وهو عدد وحدات البت -عرب األجهزة.
يضمن املعيار الحد األدنى لألحجام كما هو موضح في الجدول التالي .2.1ومع ذلك ، •
يُسمح للمرتجمني باستخدام أحجام أكرب لهذه األنواع. •
أيضا.
ونظرًا الختالف عدد وحدات البت ،فإن أكرب (أو أصغر) قيمة يمكن أن يمثلها النوع قد تختلف ً •
00011011011100010110010000111011 ...
تتعامل معظم أجهزة الكمبيوتر مع الذاكرة على أنها أجزاء من وحدات بت ذات قوة تبلغ .2 •
يشار إلى أصغر جزء من الذاكرة القابلة للعنونة باسم "بايت ."byte •
يُشار إلى وحدة التخزين األساسية ،اليت تتكون عاد ًة من عدد صغري من البايتات ،باسم "كلمة ."word •
في لغة يس ، ++يحتوي البايت على ما ال يقل عن عدد البتات املطلوبة •
ﻻستيعاب حرف في مجموعة األحرف األساسية للجهاز. •
في معظم األجهزة ،يحتوي البايت على 8بتات وتحتوي الكلمة إما على 32أو 64بت ،أي 4أو 8بايت. •
هنا ،يكون عنوان البايت على اليسار ،مع 8بتات من البايت تتبع العنوان. •
يمكن استخدام عنوان ما ليشري إلى أي من مجموعات وحدات بت عديدة مختلفة األحجام تبدأ من العنوان. •
من املمكن قول أن الكلمة على العنوان 736424أو نقول البايت على العنوان .736427 •
إلعطاء معىن للذاكرة في عنوان معني ،يجب أن نعرف نوع القيمة املخزنة هناك. •
يعرف النوع عدد البتات املستخدمة وكيفية تفسري تلك البتات. •
إذا كان الكائن في املوقع 736424يحتوي على عائمة عرشية ، float •
وتم تخزين العائمات العرشية floatsعلى هذا الجهاز في 32بت ، •
فإننا نعلم أن الكائن في هذا العنوان يمتد إلى كلمة بأكملها. •
تعتمد قيمة هذا العائم العرشي floatعلى تفاصيل كيفية تخزين اآللة ألرقام العائمة العرشية. •
بدال ً من ذلك ،إذا كان الكائن في املوقع 736424عبارة عن حرف بال_إشارة ، •
وذلك على جهاز باستخدام مجموعة أحرف ، ISO-Latin-1 •
فإن البايت املوجود في هذا العنوان تمثل فاصلة عرشية. •
باستثناء األنواع املنطقية وأنواع األحرف املوسعة ،قد تكون األنواع الصحيحة بإشارة أو بال_إشارة :
فالنوع ذو اﻹشارة signedيحتوي األرقام السالبة أو املوجبة (بما في ذلك الصفر) ؛ •
بينما يمثل النوع بال_إشارة unsignedفقط قيماً موجب ًة أكرب من أو تساوي الصفر. •
األنواع ، intو ، shortو ، longو long longكلها ذات إشارة .signed •
نحصل على النوع املقابل بال_إشارة عن طريق إضافة كلمة ال_إشارة إلى النوع ،مثل unsigned long •
قد يتم اختصار نوع intبال_إشارة unsigned intإلى unsignedفقط. •
على عكس أنواع األعداد الصحيحة األخرى ،هناك ثالثة أنواع أساسية ممزية من األحرف:
، charو charبإشارة ،و charبال_إشارة. •
على وجه الخصوص ،النوع charال يعترب نفس نوع .signed char •
وعلى الرغم من وجود ثالثة أنواع من األحرف ،إال أنه ال يوجد سوى تمثيلني :بإشارة وبال_إشارة. •
يستخدم نوع الحرف (العادي) أحد هذين التمثيلني. •
أي من التمثيالت األخرى ذات األحرف املكافئة لـ charتعتمد على املرتجم. •
تمرين :2.1
-ما هي االختالفات بني int ، long ، long long ، short؟
-وبني unsigned typeوsigned؟
-وبني floatو double؟
تمرين :2.2
-لحساب دفعة الرهن العقاري ،ما هي األنواع اليت ستستخدمها في املعدل ،واملبلغ األسايس ،واملدفوعات؟
-ارشح سبب اختيار كل نوع.
تم تصميم يس ، ++بشكل مشابه للغة يس ،حيث تسمح للربامج باالقرتاب من األجهزة عند الرضورة. •
ويتم تعريف األنواع الحسابية لتلبية الخصائص املمزية ألنواع مختلفة من األجهزة. •
وف ًقا لذلك ،يمكن أن يكون عدد األنواع الحسابية في يس ++محريًا. •
يمكن (وينبغي) ملعظم املربمجني تجاهل هذه التعقيدات من خالل تقييد األنواع اليت يستخدمونها. •
يمكن أن تكون بعض القواعد األساسية مفيدة في تحديد النوع الذي يجب استخدامه كالتالي :
استخدم النوع بال_إشارة unsignedعندما تعلم أن القيم ال يمكن أن تكون سالبة. •
استخدام عدد صحيح intللعمليات الحسابية. •
غالبا ما يكون للطويل نفس حجم intالعادي.
ً قد يكون القصري shortعادة صغريًا ج ًدا ،وعملياً ، •
إذا كانت قيم بياناتك أكرب من الحد األدنى للحجم املضمون لـ ، intفاستخدم .long long •
منطقيا boolفي التعبريات الحسابية.
ً عاديا charأو
ً ال تستخدم حر ًفا •
استخدمهما فقط لالحتفاظ باألحرف أو قيم منطقية. •
تعد العمليات الحسابية باستخدام charمشكلة بشكل خاص •
وذلك ألن الحرف charيكون بإشارة على بعض األجهزة وبال_إشارة على أجهزة أخرى. •
صحيحا صغريًا ،فحدد رصاح ًة أحر ًفا بإشارة أو أحر ًفا بال_إشارة.
ً إذا كنت تريد عد ًدا •
استخدم doubleللحساب العرشي .العائم الفردي floatعادة ال يحتوي على دقة كافية ، •
وتكلفة العمليات الحسابية ذات الدقة املزدوجة مقابل الدقة املفردة ال تكاد تذكر. •
في الواقع ،في بعض األجهزة ،تكون العمليات ذات الدقة املزدوجة أرسع من عمليات الدقة الفردية. •
وعاد ًة ما تكون الدقة اليت يوفرها املزدوج الطويل long doubleغري رضورية ، •
كذلك تستلزم غالبًا تكلفة وقت تشغيل كبرية. •
2٫1٫2تحويالت النوع
2.1.2. Type Conversions
يعر ف نوع الكائن البيانات اليت قد يحتويها الكائن والعمليات اليت يمكن أن يؤديها.
ّ
ومن بني عمليات تدعمها عدة أنواع القدرة على تحويل كائنات نوع محدد إلى أنواع أخرى ذات صلة. •
تلقائيا عندما نستخدم كائنًا من أحد اﻷنواع حيث يتوقع كائن من نوع مختلف.
ً تحدث تحويالت نوع الكائن
سيكون لدينا املزيد لنقوله عن التحويالت الح ًقا ، •
ولكن في الوقت الحالي من املفيد فهم ما يحدث عندما نخصص قيمة من نوع ما إلى كائن من نوع آخر. •
يطبق املرتجم هذه التحويالت من النوع نفسه عندما نستخدم قيمة من نوع حسابي ،
حيث يتوقع وجود قيمة نوع حسابي مختلف. •
على سبيل املثال ،عندما نستخدم قيمة غري منطقية كرشط ،
يتم تحويل القيمة الحسابية إلى قيمة منطقية بنفس الطريقة اليت سيتم بها تحويلها ، •
إذا قمنا بتعيني هذه القيمة الحسابية كمتغري منطقي: •
;int i = 42
if (i) // condition will evaluate as true
;i = 0
فإن كانت القيمة ، 0فالرشط خطأ false؛ جميع القيم األخرى (عدا الصفر) تعطي القيمة صحيح .true •
دائما إلى 0أو .1
ً منطقيا في تعبري حسابي ،تتحول قيمته
ً وعلى نفس املنوال ،عندما نستخدم نوعا •
نتيجة لذلك ،فإن استخدام نوع منطقي في تعبري حسابي يكاد يكون غري سليم. •
لسوء الحظ ،يمكن أن تبدو أن الربامج اليت تحتوي على سلوك غري معرف ، •
كأنها تتنفذ بشكل صحيح في بعض الظروف و /أو مع بعض املرتجمات. •
لكن ليس هناك ما يضمن أن برنامجا ،تمت ترجمته تحت مرتجم مختلف ، •
أو حىت إصدار الحق من نفس املرتجم ،سيستمر في العمل بشكل صحيح. •
وال يوجد أي ضمان على أن ما يعمل مع مجموعة من املدخالت سيعمل مع مجموعة أخرى. •
وباملثل ،يفرتض أن تتجنب الربامج عاد ًة طرق التعريف بالتنفيذ ، •
مثل افرتاض أن حجم intهو قيمة ثابتة ومعروفة. •
يقال أن مثل هذه الربامج غري قابلة للنقل. •
فعندما يتم نقل الربنامج إلى جهاز آخر ،قد تفشل األكواد اليت تعتمد على طرق التعريف بالتنفيذ. •
إن تعقب هذه األنواع من املشاكل في الربامج اليت كانت تعمل ساب ًقا هو ،باعتدال أمر غري سار.
على الرغم من أنه من غري املحتمل أن نعنّي عن قصد قيمة سالبة لكائن نوع بال_إشارة ،
ضمنيا.
ً يمكننا (بكل سهولة) كتابة كود يفعل ذلك •
على سبيل املثال ،إذا استخدمنا قيماً بال_إشارة unsignedمع قيمة صحيحة في تعبري حسابي ، •
يتم تحويل القيمة الصحيحة عاد ًة إلى قيمة بال_إشارة .unsigned •
يتم تنفيذ تحويل intإلى بال_إشارة بنفس الطريقة ، •
كما لو أننا نقوم بتعيني القيمة الصحيحة كقيمة بال_إشارة : •
;unsigned u = 10
int i ;= -42
std::cout << i + i << std::endl; // prints -84
std::cout << u + i << std::endl; // if 32-bit ints, prints 4294967264
قد نعتقد أنه يمكننا إعادة كتابة هذه الحلقة باستخدام متغري بدون إشارة.
بعد كل يشء ،نحن ال نخطط لطباعة أرقام سالبة .ومع ذلك ، •
فإن هذا التغيري البسيط في النوع يعين أن حلقتنا لن تنتهي أب ًدا : •
// WRONG: u can never be less than 0; condition will always succeed
)for (unsigned u = 10; u >= 0; --u
;std::cout << u << std::endl
unsigned u = 11; // start loop one past first element we want to print
{ )while (u > 0
;--u // decrement first, so that last iteration will print 0
;std::cout << u << std::endl
}
يمكن أن تؤدي التعبريات اليت تجمع بني القيم ذات اﻹشارة والال_إشارة إلى نتائج مفاجئة ، •
عندما تكون القيمة ذات اﻹشارة سالبة. •
تلقائيا إلى قيم بال_إشارة.
ً من الرضوري أن تتذكر أنه يتم تحويل القيم ذات اﻹشارة •
على سبيل املثال ،في تعبري مثل ، a * bإذا كانت aتساوي 1-و bتساوي ، 1 •
ٍ
فعندئذ إذا كان كل من aو bعبارة عن ، intsتكون القيمة كما هو متوقع .1- •
لكن إذا كانت a intو bبال_إشارة ، •
فإن قيمة هذا التعبري تعتمد على عدد بتات intعلى الجهاز املعني. •
ينتج عن هذا التعبري على أجهزتنا .4294967295 •
تمرين :2.3
ما هي املخرجات الذي سينتجه الكود التالي؟
;unsigned u = 10, u2 = 42
std::cout << u2 - u ;<< std::endl
std::cout << u ;- u2 << std::endl
تمرين :2.4
برنامجا للتحقق مما إذا كانت توقعاتك صحيحة.
ً -اكتب
-إذا لم يكن األمر كذلك ،فقم بدراسة هذا القسم حىت تفهم ماهية املشكلة.
2٫1٫3الحرفيات
2.1.3. Literals
تُعرف قيمة ،مثل ، 42بالحرفية Literalألن قيمتها بديهية .فلكل حرفية نوع.
صياغة وقيمة الحرفية يحدد نوعها. •
على سبيل املثال ،يمكننا كتابة القيمة 20بأي من الطرق الثالث التالية:
* هيكساديسيمال سدايس عرشي * / 0x14 * أوكتال ثماني * 024 * ديسيمال عرشي * 20
سرنى في الجدول 2.2أنه يمكننا تجاوز هذه اإلعدادات االفرتاضية باستخدام الحقة.
الجدول .2.2تحديد نوع حرفي
رمز
أقل نوع رمز اإللحاق النوع املعىن
البداية
Unsignedبدون إشارة uأو U char16_t ترمزي يونيكود 16حرف u
Longعدد صحيح طويل lأو L char32_t ترمزي يونيكود 32حرف U
Long longعدد صحيح أطول llأو LL wchar_t حرف موسع L
char صيغة التحويل املوحد utf-8قيم u8
حرفيات أعداد فاصلة عرشية
مصنفة نصية فقط
floating-point literals
بالرغم من أنه يسمح بتخزين حرفيات األعداد الصحيحة في أنواع بإشارة ،
سالبا أب ًدا.
ً رقما
إﻻ أنه من الناحية الفنية ،ﻻ تعد الحرفية العرشية ً •
جزءا من الحرفية.
ً فإذا كتبنا ما يبدو أنه حرفية عرشية سالبة ،مثالً ، 42-فال تعد عالمة الطرح •
عالمة الطرح هي عامل ينفي حرفية معامله. •
نوع حرفية سلسلة عبارة عن مصفوفة من أحرف ثابتة ،وهو نوع سنناقشه في الفصل الثالث.
فارغا (’\ )’0بكل حرفية سلسلة.
ً يُلحق املرتجم حر ًفا •
وبالتالي ،فإن الحجم الفعلي لحرفية سلسلة تزيد بمقدار واحد عن حجمها الظاهري. •
فمثالً ،تمثل الحرفية ‘ ’Aالحرف املفرد ، A •
بينما تمثل حرفية السلسلة " "Aمصفوفة من حرفني ،حرف Aوالحرف الفارغ. •
تسلسل الهروب
Escape Sequences
بعض اﻷحرف ليس لها صورة مرئية -مثل املسافة لخلف أو أحرف تحكم.-
هذه األحرف غري قابلة للطباعة. •
األحرف األخرى لها معىن خاص في اللغة ، •
(كعالمات االقتباس املفردة واملزدوجة وعالمة االستفهام والرشطة املائلة للخلف). •
ال يمكن لربامجنا استخدام أي من تلك األحرف مبارشة .بدال ً من ذلك ، •
نستخدم تسلسل الهروب لتمثل تلك األحرف. •
يبدأ تسلسل الهروب برشطة مائلة للخلف .تحدد اللغة عدة تسلسالت هروب :
كما هو الحال مع تسلسل الهروب الذي تعرفه اللغة ،نستخدم تسلسالت الهروب هذه كما نستخدم أي حرف آخر:
الحظ ،
متبوعا بأكرث من ثالثة أرقام ثمانية ،فسرتبط به الثالثة األولى فقط.
ً أنه إن كان الباك-فالش \ •
على سبيل املثال ،يمثل "\ "1234حرفني :الحرف الذي يتم تمثيله بالتمثيل الثماني 123والحرف .4 •
في املقابل ،يستخدم \ الباك-فالش املتبوع بـ xجميع األرقام السداسية اليت تليها ؛ •
فيمثل "\ "x1234حر ًفا واح ًدا من 16بت يتكون من البتات املقابلة لهذه األرقام السدايس-عرش األربعة. •
ونظرًا ألن معظم األجهزة تحتوي على أحرف 8بت ،فمن غري املحتمل أن تكون هذه القيم مفيدة. •
في العادة ،يتم استخدام األحرف السداسية العرشية اليت تحتوي على أكرث من 8بتات ، •
مع مجموعات األحرف املمتدة باستخدام إحدى الرموز البادئة من جدول .2.2 •
يمكننا تجاوز النوع االفرتايض لحرفية عدد صحيح أو فاصلة عرشية أو أحرف ،
من خالل توفري الحقة أو بادئة كما سبق وذكرنا في الجدول .2.2 •
أفضل ممارسة
عندما تكتب حرفية قيمة طويلة ، long literalاستخدم حرف Lالكبري ؛
إذ من السهل ج ًدا الخلط بني حرف lالصغري والرقم .1
يمكننا وبشكل مستقل تحديد اإلشارة واملقاس لحرفي عدد صحيح. •
إذا كانت الالحقة تحتوي على حرف ، Uفإن نوع قيمة الحرفي هو نوع بال_إشارة، •
ولذا فإن الحرفي العرشي أو الثماني أو السدايس عرشي مع الحقة ، U •
يكون أصغر نوع من intبال_إشارة أو longبال_إشارة ،أو long longبال_إشارة •
بحيث تناسب القيمة الحرفية. •
إذا كانت الالحقة تحتوي على حرف ، Lفسيكون نوع قيمة الحرفي longعلى األقل ؛ •
أما إذا كانت الالحقة تحتوي على ، LL •
فسيكون نوع الحرفي إما long longأو long longبال_إشارة. •
ويمكننا دمج Uمع Lأو .LL •
فمثالً ،ستكون حرفية لها الحقة ULإما longبال_إشارة أو long longبال_إشارة ، •
اعتما ًدا على ما إذا كانت قيمتها تتناسب مع longبال_إشارة. •
أما الكلمة nullptrعبارة عن حرفية مؤرش .سيكون لدينا املزيد لنقوله عن املؤرشات و nullptrﻻحقاً.
تمرين :2.5
-حدد نوع كل من الحرفيات التالية.
-ارشح االختالفات بني العنارص الحرفية في كل من األمثلة األربعة:
"(a) 'a', L'a', "a", L"a
(b) 10, 10u, 10L, 10uL, 012, 0xC
(c) 3.14, 3.14f, 3.14L
(d) 10, 10u, 10., 10e-2
تمرين :2.6
ما هي االختالفات ،إن وجدت ،بني التعريفات التالية:
int month = 9, day ;= 7
;int month = 09, day = 07
تمرين :2.7
-ما هي القيم اليت تمثلها هذه القيم؟
-ما نوع كل منها؟
"(a) "Who goes with F\145rgus?\012
(b) 3.14e1L
(c) 1024f
(d) 3.14L
تمرين :2.8
متبوعا بسطر جديد.
ً برنامجا لطباعة 2M
ً -باستخدام تسلسل الهروب ،اكتب
متبوعا بسطر جديد.
ً -قم بتعديل الربنامج لطباعة ، 2ثم حرف تاب ،ثم ، M
. 2٫2املتــــــــــغيـــــــــــرات
2.2. Variables
يوفر لنا املتغري مخزناً مسمى يمكن لربامجنا معالجته .فكل متغري في يس ++له نوع.
ً
• يحدد النوع حجم ذاكرة املتغري وتنسيقها ،ونطاق القيم اليت يمكن تخزينها في تلك الذاكرة ،
وكذلك مجموعة العمليات اليت يمكن تطبيقها على املتغري. •
يميل مربمجو يس ++إلى اﻹشارة إلى املتغريات باسم "متغريات ، "variables •
أو "كائنات "objectsبالتبادل. •
2٫2٫1تعريفات املتغري
2.2.1. Variable Definitions
int sum = 0, value, // sum, value, and units_sold have type int
;units_sold = 0 //sum and units_sold have initial value 0
;Sales_item item // item has type Sales_item
// string is library type,
// representing variable-length sequence of characters
;)"std::string book("0-201-78345-X // book initialized from string
يميل مربمجو يس ++إلى أن يكونوا متعجرفني في استخدامهم ملصطلح الكائن. •
بشكل عام ،يعترب الكائن منطقة من الذاكرة يمكن أن تحتوي على بيانات ولها نوع. •
يستخدم البعض مصطلح كائن فقط لإلشارة إلى متغريات أو قيم أنواع فئة. •
يمزي البعض اآلخر بني كائنات مسماة وغري مسماة ، •
باستخدام املصطلح متغري Variableليشري إلى الكائنات املسماة. •
ال يزال البعض اآلخر يمزي بني الكائنات والقيم ، •
باستخدام املصطلح كائن Objectللبيانات اليت يمكن تغيريها بواسطة برنامج، •
واستخدام املصطلح قيمة Valueللبيانات اليت تكون للقراءة فقط. •
في هذا الكتاب ،سنتبع االستخدام األكرث عمومية بأن الكائن Objectهو منطقة من الذاكرة لها نوع. •
سنستخدم املصطلح كائن Objectبحرية بغض النظر ، •
عما إذا كان الكائن يحتوي على نوع مدمج أو نوع فئة ، •
أو مسمى أو غري مسمى ،أو يمكن قراءته أو كتابته. •
املهيئات
Initializers
وتكرارا.
ً مرارا
ً التهيئة في يس ++موضوع معقد بشكل مدهش وسنعود إليه
يتم الخلط بني العديد من املربمجني في استخدام الرمز = لتهيئة متغري. •
من املغري التفكري في التهيئة كشكل من أشكال التعيني ،إﻻ أنهما عمليتان مختلفتان في يس.++ •
هذا املفهوم محري بشكل خاص ألنه في العديد من اللغات يكون التميزي غري ذي صلة ويمكن تجاهله. •
غالبا ما يكون التميزي غري مهم .ومع ذلك ،
ً عالوة على ذلك ،حىت في يس، ++ •
فهو مفهوم أسايس وسنكرره خالل الكتاب. •
تحذير
التهيئة ليست هي التعيني.
تحدث التهيئة عندما يتم إعطاء متغري قيمة ما عند إنشائه. •
بينما يطمس التعيني القيمة الحالية للكائن ويستبدل تلك القيمة بقيمة جديدة. •
تهيئة القائمة
List Initialization
تم تقديم االستخدام العام لألقواس املتعرجة في التهيئة كجزء من املعيار الجديد.
مسموحا به لكن بطرق أكرث تقيي ًدا.
ً كان هذا الشكل من التهيئة ساب ًقا •
ألسباب سنتعرف عليها ﻻحقا ،يشار إلى هذا الشكل من التهيئة باسم تهيئة القائمة. •
يمكن اآلن استخدام القوائم ذات اﻷقواس للتهيئة كلما قمنا بتهيئة كائن ، •
وفي بعض الحاالت عندما نقوم بتعيني قيمة جديدة لكائن. •
يتمتع نموذج التهيئة هذا بخاصية مهمة عند استخدام هذا النوع من التهيئة على متغريات نوع مدمج : •
املهيِـئ قد يؤدي إلى فقدان معلومات:
ّ لن يسمح املرتجم لنا بتهيئة قائمة متغريات نوع مدمج إذا كان •
التهيئة اﻻفرتاضية
Default Initialization
افرتاضيا.
ً مهيِـئ ،يتم تهيئة املتغري
عندما نعرف متغريًا بدون ّ
• مثل هذه املتغريات تعطي قيمة "افرتاضية".
أيضا على مكان تعريف املتغري.
تعتمد القيمة االفرتاضية على نوع املتغري وقد تعتمد ً •
تعتمد قيمة كائن من نوع مدمج لم تتم تهيئته بشكل رصيح على مكان تعريفه.
فيتم تهيئة املتغريات املعرفة خارج أي بنية دالة على الصفر .باستثناء واحد ،سنغطيه في الفقرة ، 6.1.1 •
تكون متغريات النوع املدمج املعرفة داخل دالة غري مهيأة. •
معرف.
قيمة متغري غري مهيأ من النوع املدمج يعطي سلوكاً غري ّ •
معرفة.
ومن الخطأ نسخ أو محاولة الوصول إلى قيمة متغري تكون قيمته غري ّ •
مثالً ،وكما رأينا للتو ،تقول فئة مكتبة السلسلة أنه إذا لم نوفر ُمهيًئ ا ،فإن السلسلة الناتجة سلسلة فارغة:
ملحوظة
الكائنات غري املهيأة من النوع املدمج واملعرفة داخل بنية دالة قيمتها غري معرفة.
الكائنات من نوع الفئة اليت ال نقوم بتهيئتها رصاحة قيمتها تعرف عن طريق الفئة.
تمرين :2.9
-ارشح التعاريف التالية.
-بالنسبة لتلك اليت تعترب غري رشعية ،ارشح ما هو الخطأ وكيفية تصحيحه.
معرفة.
املتغري غري املهيأ يحمل قيمة غري ّ •
غالبا تصحيحه .عالوة على ذلك ،
ً تعد محاولة استخدام قيمة متغري غري مهيأ خطأ يصعب •
ال يُطلب من املرتجم اكتشاف مثل هذه األخطاء ، •
بالرغم من أن معظمها ستحذر على األقل من بعض استخدامات املتغريات غري املهيأة. •
ما يحدث عندما نستخدم متغريًا غري مهيأ هو سلوك غري معرف. •
أحياناً ،نكون محظوظني ويتعطل برنامجنا بمجرد وصولنا إلى الكائن. •
بمجرد أن نتعقب موقع االنهيار ،فمن السهل عادة رؤية أن املتغري لم تتم تهيئته بشكل صحيح. •
بينما في أوقات أخرى ،يكتمل الربنامج ولكن ينتج عنه نتائج خاطئة. •
واألسوأ من ذلك ،قد تظهر النتائج صحيحة في تشغيل ما لربنامجنا ولكنها تفشل في تشغيل الحق. •
عالوة على ذلك ،فإن إضافة كود إلى الربنامج في مكان غري ذي صلة ... •
يمكن أن يؤدي إلى ما اعتقدنا أنه برنامج صحيح يبدأ إنتاج نتائج خاطئة. •
تلميح
دائما ،ولكن
ً نويص بتهيئة كل كائن نوع مدمج .ليس من الرضوري
املهيِـئ.
ّ مهيِـئ حىت يمكنك التأكد من أنه من اآلمن حذف
من األسهل واألكرث أما ًنا توفري ّ
لدعم التجميع املنفصل ،تمزي لغة يس ++بني اإلعالنات والتعريفات. •
فاإلعالن يجعل االسم معرو ًفا للربنامج. •
حيث يتضمن امللف الذي يريد استخدام اسم معرف في مكان آخر إعالناً بذلك االسم. •
يعرف إعالن متغري ما نوع واسم املتغري .أما التعريف فينئش الكيان املرتبط.
ّ •
تعريف املتغري يعترب إعالناً .فإضافة إلى تحديد االسم والنوع ، •
أيضا مخزناً للمتغري وقد يزوده بقيمة أولية.
يخصص ً •
رصيحا:
ً أيضا ،نضيف كلمة externاألساسية وقد ال نقدم ُمهيًئ ا
للحصول على إعالن ﻻ يعد تعري ًفا ً
;extern int i // declares but does not define I
;int j // declares and defines j
ملحوظة
يتوجب تعريف املتغريات مرة واحدة فقط لكن يمكن اإلعالن عنها عدة مرات.
يس ++هي لغة مكتوبة بشكل ساكن ،ما يعين أنه يتم فحص األنواع في وقت الرتجمة. •
يشار إلى العملية اليت يتم من خاللها فحص األنواع باسم فحص النوع .type checking •
كما رأينا ،فإن نوع الكائن يقيد العمليات اليت يمكن أن يؤديها الكائن. •
في يس ، ++يتحقق املرتجم ما إذا كانت العمليات اليت نكتبها مدعومة من قبل األنواع اليت نستخدمها. •
فإذا حاولنا القيام بأشياء ال يدعمها النوع ، •
سيقوم املرتجم بإنشاء رسالة خطأ وال ينتج مل ًفا قابالً للتنفيذ. •
ومع ازدياد تعقيد برامجنا ،سرنى أن فحص النوع الساكن يمكن أن يساعد في العثور على األخطاء. •
مع ذلك ،فإن أهمية الفحص الساكن هي أن نوع كل كيان نستخدمه يجب أن يعرفه املرتجم. •
كمثال ،يجب أن نعلن عن نوع املتغري قبل أن نتمكن من استخدامه. •
2٫2٫3املعرفات
2.2.3. Identifiers
التمرين :2.12
أي من األسماء التالية غري صالحة ،إن وجدت؟
;(a) int double = 3.14
;_ (b) int
;(c) int catch-22
;(d) int 1_or_2 = 1
;(e) double Double = 3.14
2٫2٫4نطاق اسم
2.2.4. Scope of a Name
>#include <iostream
{ )(int main // sum values from 1 through 10 inclusive
;int sum = 0
)for (int val = 1; val <= 10; ++val
;sum += val // equivalent to sum = sum + val
std::cout ;<< "Sum of 1 to 10 inclusive is " << sum << std::endl
} ;return 0
من الجيد عاد ًة تعريف كائن بالقرب من النقطة اليت تم استخدام الكائن عندها ألول مرة. •
يؤدي القيام بذلك إلى تحسني قابلية القراءة من خالل تسهيل العثور على تعريف املتغري. •
غالبا ما يكون من األسهل إعطاء املتغري قيمة أولية مفيدة ،
ً واألهم من ذلك ،أنه •
عندما يتم تعريف املتغري بالقرب من مكان استخدامه ألول مرة. •
النطاقات املتداخلة
Nested Scopes
>#include <iostream
// Program for illustration purposes only: It is bad style for a function
// to use a global variable and also define a local variable with same name
;int reused = 42 // reused has global scope
)(int main {
;int unique = 0 // unique has block scope
// output #1: uses global reused; prints 42 0
;std::cout << reused << " " << unique << std::endl
int reused = 0; // new, local object named reused hides global reused
// output #2: uses local reused; prints 0 0
;std::cout << reused << " " << unique << std::endl
// output #3: explicitly requests the global reused; prints 42 0
;std::cout << ::reused << " " << unique << std::endl
;return 0 }
تظهر املخرجات رقم 1قبل التعريف املحلي لـ .reused •
لذلك ،تستخدم جملة املخرجات االسم reusedاملعرف في النطاق العام. •
تطبع هذه الجملة .0 42 •
تحدث املخرجات رقم 2بعد التعريف املحلي لـ .reused •
reusedاملحلية اآلن في النطاق. •
بالتالي ،تستخدم جملة املخرجات الثانية الكائن املحلي بدال ً من الكائن العام ويطبع .0 0 •
تستخدم املخرجات رقم 3عامل النطاق ( )::لتجاوز قواعد تحديد النطاق االفرتاضية. •
ليس للنطاق العام اسم. •
ومن ثم ،عندما يكون لعامل النطاق جانب أيرس فارغ ، •
طلبا لجلب اسم على الجانب األيمن من النطاق العام.
ً فهذا يكون •
وبالتالي ،يستخدم كائن reusedالعام ويطبع .0 42 •
تحذير
غالب ا ما تكون فكرة سيئة تعريف متغري محلي يحمل نفس اسم متغري عام تستخدمه الدالة أو قد تستخدمه.
ً
تمرين :2.13
-ما هي قيمة jفي الربنامج التالي؟
;int i = 42
{ )(int main
;int i = 100
;int j = i
}
التمرين :2.14
-هل الربنامج التالي رشعي؟
-إذا كان األمر كذلك ،فما هي القيم املطبوعة؟
;int i = 100, sum = 0
)for (int i = 0; i != 10; ++i
;sum += i
;std::cout << i << " " << sum << std::endl
. 2٫3األنــــــــــواع الــــمــــركــــبــــــــــة
يعد تعريف متغريات من النوع املركب من أكرث التعريفات اليت رأيناها تعقي ًدا حىت اآلن.
فقد قلنا في الفقرة 2.2أن اإلعالنات البسيطة تتكون من نوع يتبعه قائمة بأسماء املتغريات. •
متبوعا بقائمة من اإلعالنات.
ً أساسيا
ً نوعا
بشكل عام ،يعترب اإلعالن ً •
مرتبطا بالنوع األسايس.
ً نوعا
يقوم كل إعالن بتسمية متغري ويعطي املتغري ً •
2٫3٫1املراجع
2.3.1. References
ملحوظة
قدم املعيار الجديد نوع مرجع جديد rvalue reference“ :مرجع قيمة يمىن” ، •
سنغطيه في الفقرة .13.6.1 •
تلك املراجع مخصصة بشكل أسايس لالستخدام داخل الفئات .classes •
أما إذا تحدثنا فنياً :عندما نستخدم مصطلح املرجع ، •
فإننا نعين " lvalue referenceمرجع قيمة يرسى". •
نعرف نوع املرجع من خالل كتابة ُمع ِلن على شكل ، &dحيث يكون dهو االسم الذي يتم اإلعالن عنه:
ّ
ملحوظة
املرجع ليس كائنًا .بالعكس ،املرجع هو مجرد اسم آخر لكائن موجود بالفعل.
بعد تعريف مرجع ،فإن جميع العمليات على هذا املرجع تعترب في الواقع عمليات على الكائن املرتبط به؛
فعندما نعني على مرجع ،فإننا نعني على الكائن املرتبط باملرجع. •
وعندما نجلب قيمة مرجع ،فإننا بالفعل نجلب قيمة الكائن املرتبط باملرجع. •
كمهيِـئ ،فإننا بالفعل نستخدم الكائن الذي يرتبط به املرجع :
ّ مرجعا
ً وباملثل ،عندما نستخدم •
// ok: refVal3 is bound to object to which refVal is bound, i.e. to ival
;int &refVal3 = refVal
// initializes i from the value in object to which refVal is bound
;int i = refVal // ok: initializes i to same value as ival
ٍ
مرجع ملرجع. ونظرًا ألن املراجع ليست كائنات ،فال يسمح لنا تعريف
تعريفات مرجع
Reference Definitions
int i = 1024, i2 ;= 2048 // i and i2 both ints
int &r = i, r2 ;= i2 // r reference bound to i; r2 int
int i3 = 1024, ;&ri = i3 // i3 int; ri reference bound to i3
int &r3 = i3, ;&r4 = i2 // both r3 and r4 references
مع استثناءين سنغطيهما في الفقرتني 2.4.1والفقرة ، 15.2.3
تماما.
ً يجب أن يتطابق نوع املرجع والكائن الذي يشري إليه املرجع •
عالوة على ذلك ،وألسباب سنستكشفها في الفقرة ، 2.4.1 •
ﻻ يرتبط املرجع إﻻ بكائن ،وليس بقيمته الحرفية أو نتيجة تعبري أكرث عمومية : •
التمرين :2.15
أي من التعريفات التالية ،إن وجدت ،غري صالحة؟ ملاذا ؟
;(a) int ival = 1.01
;(b) int &rval1 = 1.01
;(c) int &rval2 = ival
;(d) int &rval3
التمرين :2.16
-أي من التعيينات التالية غري صالحة ،إن وجدت؟
-إذا كانت صحيحة ،فارشح ما تفعله.
;int i = 0, &r1 = i; double d = 0, &r2 = d
;(a) r2 = 3.14159
;(b) r2 = r1
;(c) i = r2
;(d) r1 = d
التمرين :2.17
-ماذا يطبع الكود التالي؟
;int i, &ri = i
;i = 5; ri = 10
;std::cout << i << " " << ri << std::endl
2٫3٫2املؤرشات
2.3.2. Pointers
تحذير
غالب ا ما يصعب فهم املؤرشات .مشاكل التصحيح بسبب أخطاء املؤرش تربك حىت املربمجني ذوي الخربة.
ً
int ;*ip1, *ip2 // both ip1 and ip2 pointers to int
double ;dp, *dp2 // dp2 pointer to double; dp double
يحمل مؤرش ما عنوان كائن آخر .حيث نحصل على عنوان كائن عن طريق عامل العنوان (&) :
تُع ِّرف الجملة الثانية pكمؤرش على intوتهئي pلتشري لكائن intمسمى .ival •
ونظرًا ألن املراجع ليست كائنات ،فليس لها عناوين .ومن ثم ،ال يسمح بتعريف مؤرش ملرجع. •
مع استثناءين ،نغطيهما في الفقرتني 2.4.2والفقرة ، 15.2.3يجب أن يتطابق نوع املؤرش والكائن الذي يشري إليه:
;double dval
double *pd = &dval; // ok: initializer is address of a double
;double *pd2 = pd // ok: initializer is pointer to double
int *pi ;= pd // error: types of pi and pd differ
;pi = &dval // error: assigning address of double to pointer to int
يجب أن تتطابق األنواع ألن نوع املؤرش يُستخدم ملعالجة نوع كائن يشري إليه املؤرش.
إذا عالج املؤرش كائنًا من نوع آخر ،فستفشل العمليات اليت يتم إجراؤها على الكائن األسايس.
قيمة املؤرش
Pointer Value
يمكن أن تكون القيمة (أي العنوان) املخزنة في املؤرش واحدة من أربع حاالت:
.1يمكن أن يشري إلى كائن.
.2يمكن أن يشري إلى املوقع مـا بعد نهاية الكائن.
فارغا يشري إلى أنه غري مرتبط بأي كائن.
ً .3يمكن أن يكون مؤرشًا
.4يمكن أن يكون غري صالح .القيم األخرى غري الثالثة السابقة غري صالحة.
من الخطأ نسخ أو محاولة الوصول إلى قيمة مؤرش غري صالح.
كما هو الحال عندما نستخدم متغريًا غري مهيأ ،فإن خطأ كهذا من غري املحتمل أن يكتشفه املرتجم. •
نتيجة الوصول إلى مؤرش غري صالح سلوك غري معرف. •
صالحا أم ال.
ً دائما ما إذا كان املؤرش املعني
ً لذلك ،يجب أن نعرف •
عندما يشري مؤرش لكائن ،يمكننا استخدام عامل إلغاء املرجع ،الذي يُشار إليه بعالمة (النجمة *) للوصول لهذا
الكائن :
إلغاء املرجع عن مؤرش ينتج عنه قيمة الكائن الذي يشري إليه املؤرش.
يمكننا التعيني على هذا الكائن عن طريق التعيني لنتيجة إلغاء املرجع :
;*p = 0 // * yields object; assign new value to ival by p
;cout << *p // prints 0
عندما نعني على ، *pفإننا نعني على الكائن الذي يشري إليه .p
ملحوظة
ﻻ يسمح بإلغاء املرجع إﻻ عن مؤرش صالح يشري لكائن.
تُستخدم بعض الرموز ،مثل & و * ،كعامل في تعبري وكجزء من إعالن. •
يحدد السياق الذي يستخدم فيه الرمز ما يعنيه الرمز: •
;Int I = 42
;int &r = i & //يتبع النوع وهو جزء من إعالن r .عبارة عن مرجع
;int *p * //يتبع النوع وهو جزء من إعالن p .عبارة عن مؤرش
p ;= &i & //يستخدم في تعبري على أنه عامل العنوان
;*p = i * //في تعبري عل يستخدم ى أنه عامل إلغاء املرجع
;int &r2 = *p & //هو جزء من إعالن * .هو عامل إلغاء املرجع
املؤرشات الفارغة
Null Pointers
الطريقة األكرث مبارشة هي تهيئة املؤرش على الحرفية ، nullptrواملقدمة بواسطة املعيار الجديد. •
الحرفية nullptrعبارة عن حرفية لها نوع خاص يمكن تحويلها إلى أي نوع مؤرش آخر. •
وكبديل ،يمكننا تهيئة مؤرش على الحرفية ، 0كما نفعل في التعريف .p2 •
يعرفه العنوان cstdlibبالقيمة (.)0
تستخدم الربامج األقدم أحيا ًنا متغري معالجاً أولياً يسمى ّ ، NULL
• سنقوم بوصف املعالج اﻷولي بمزيد من التفصيل في الفقرة . 2.6.3
ما هو مفيد أن تعرفه اآلن هو أن املعالج اﻷولي هو برنامج يتم تشغيله قبل املرتجم. •
جزءا من مساحة االسم .std
ً تتم إدارة متغريات املعالج اﻷولي بواسطة املعالج اﻷولي نفسه ،وهي ليست •
ونتيجة لذلك ،نشري إليها مبارشة بدون .std::prefix •
تلقائيا بقيمته.
ً عندما نستخدم متغري املعالج اﻷولي ،فإن املعالج األولي يستبدل املتغري
وبالتالي ،فإن تهيئة مؤرش على NULLتعادل تهيئته إلى .0 •
عموما استخدام NULLوتستخدم nullptrبدال ً منها.
ً يجب أن تتجنب برامج يس ++الحديثة •
ومن غري الرشعي تعيني املؤرش على متغري عدد صحيح ،حىت لو صادفت قيمة املتغري صفر. •
التعيني واملؤرشات
Assignment and Pointers
;int i = 42
;int *pi = 0 // pi is initialized but addresses no object
;int *pi2 = &i // pi2 initialized to hold the address of i
;int *pi3 // if pi3 defined inside block, pi3 uninitialized
;pi3 = pi2 // pi3 and pi2 address the same object, e.g., i
;pi2 = 0 // pi2 now addresses no object
قد يكون من الصعب البقاء على مسار مستقيم سواء كان التعيني يغري املؤرش أو الكائن الذي يشري إليه املؤرش.
اليشء املهم الذي يجب مراعاته هو أن التعيني يغري معامله األيرس .فعندما نكتب
فإننا نقوم بتعيني قيمة جديدة لـ ، piمما يغري العنوان الذي يحمله .pi
مؤرشات *void
void* Pointers
ومثل أي مؤرش آخر ،يحمل املؤرش * voidعنوا ًنا ،إﻻ أن نوع الكائن في هذا العنوان غري معروف بعد :
ال يوجد الكثري مما يمكن القيام به باستخدام مؤرش *: void
فيمكننا مقارنته بمؤرش آخر ،أو تمريره أو إعادته من دالة ،ويمكننا تعيينه على مؤرش * voidآخر. •
ال يمكننا استخدام * voidللعمل على كائن يعالجه – فنحن ال نعرف نوعه بعد ، •
فالنوع يحدد تلك العمليات اليت يمكننا إجراؤها على الكائن. •
بشكل عام ،
نستخدم مؤرش * voidللتعامل مع الذاكرة كذاكرة ،بدال ً من الوصول لكائن مخزن في تلك الذاكرة. •
سنغطي استخدام مؤرشات * voidبهذه الطريقة في الفقرة . 19.1.1 •
ستوضح فقرة 4.11.3كيف يمكننا اسرتداد عنوان مخزن في مؤرش *. void •
التمرين :2.18
-اكتب جملة برمجية لتغيري قيمة املؤرش.
-اكتب كود لتغيري القيمة اليت يشري إليها املؤرش.
التمرين :2.19
-ارشح االختالفات األساسية بني املؤرشات واملراجع.
تمرين :2.20
ماذا يفعل الربنامج التالي؟
int I ;= 42
;int *p1 = &i
*p1 ;= *p1 * *p1
تمرين :2.21
-ارشح كاًل من التعريفات التالية.
-وضح ما إذا كان أي منها غري رشعي ،وإذا كان األمر كذلك ،فلماذا.
;int i = 0
;(a) double* dp = &i
(b) int *ip ;= i
(c) int *p ;= &i
التمرين :2.22
بافرتاض أن pهي مؤرش إلى ، intفرس الكود التالي:
if (p) // ...
if (*p) // ...
التمرين :2.23
-عند إعطاء املؤرش ، pهل يمكنك تحديد ما إذا كانت pتشري إلى كائن صالح؟
-إذا كان األمر كذلك ،فكيف؟
-إذا لم يكن كذلك ،فلماذا؟
التمرين :2.24
-ملاذا يعترب تهيئة pرشعياً بينما تهيئة lpغري رشعي؟
;int i = 42
;void *p = &i
;long *lp = &i
تحذير
جزءا من ُمع ِلن.
ً يرتبك العديد من املربمجني بشأن التفاعل بني النوع األسايس وتعديل النوع الذي قد يكون
هناك نوعان من األنماط الشائعة املستخدمة لتعريف متغريات متعددة باستخدام املؤرش أو نوع املرجع.
املعرف:
ّ معدل النوع بجوار
األول يضع ّ
مركبا.
ً نوعا
يعرف ً
يؤكد هذا النمط على أن اإلعالن ّ
تلميح
ال توجد طريقة صحيحة لتعريف املؤرشات أو املراجع .اليشء املهم هو اختيار نمط واستخدامه باستمرار. •
نستخدم في هذا الكتاب النمط األول ونضع * (أو &) مع اسم املتغري. •
مؤرشات ملؤرشات
Pointers to Pointers
ما يعين أننا نكتب ** من أجل مؤرش ملؤرش ،و *** من أجل مؤرش ملؤرش ملؤرش ،وهكذا دواليك :
وكما أن إلغاء مرجع عن مؤرش لعدد صحيح ينتج عنه عدد صحيح ، •
فإن إلغاء مرجع عن مؤرش ملؤرش سينتج عنه مؤرش. •
وللوصول إلى الكائن األسايس ،يجب علينا إلغاء املرجع عن املؤرش األصلي مرتني :
مراجع ملؤرشات
References to Pointers
املرجع ليس كائنًا .ومن ثم ،ال يسمح أن يكون لدينا مؤرش ملرجع .لكن ،
ونظرًا ألن املؤرش عبارة عن كائن ،فيمكننا تعريف مرجع ملؤرش :
;int i = 42
;int *p // p pointer to int
;int *&r = p // r reference to pointer p
r ;= &i ;// r refers to pointer
// assigning &i to r makes p point to i
;*r = 0 // dereferencing r yields i,
// object to which p points; changes i
to 0
أسهل طريقة لفهم نوع rهي قراءة التعريف من اليمني إلى اليسار.
فالرمز األقرب إلى اسم املتغري (في حالتنا & في )&rهو الرمز ذو التأثري الفوري على نوع املتغري. •
بالتالي ،نعلم أن rمرجع .يحدد بقية املُع ِلن النوع الذي يشري إليه .r •
يُخرب الرمز التالي وهو في هذه الحالة * إلى أن النوع rيشري لنوع مؤرش. •
أخريًا ،يخرب النوع األسايس لإلعالن أن rهو مرجع مؤرش لعدد صحيح. •
تلميح
قد يكون من األسهل فهم اإلعالنات املعقدة ملؤرش أو مرجع إن قُرأت من اليمني إلى اليسار.
تمرين :2.25
حدد أنواع وقيم كل من املتغريات التالية.
(a) int* ip, ;&r = ip
(b) int i, ;*ip = 0
(c) int* ip, ;ip2
. 2٫4املقيـــــــــــد ثابــــــــــت
2.4. const Qualifier
يمكننا جعل املتغري غري قابل للتغيري عن طريق تعريف نوع املتغري كـ ثابت : const
ونظرًا ألنه ال يمكننا تغيري قيمة كائن ثابت بعد إنشائه ،فيجب تهيئته.
التهيئة والثابت
Initialization and const
;const int ci = i // ok: the value in i copied into ci
;int j = ci // ok: the value in ci copied into j
بالرغم من كون ciعدداً صحيحاً ثابتاً ،فإن القيمة في ciعدد صحيح. •
لن يهم ثبات ciإال لعمليات قد تغري قيمته. •
فعندما ننسخ ciلتهيئة ، jال نهتم بأن ciثابتة. •
ال يؤدي نسخ كائن إلى تغيري ذلك الكائن. •
لكن بمجرد عمل النسخة ،ال يمكن للكائن الجديد الوصول إلى الكائن األصلي. •
عندما يتم تهيئة كائن ثابت على ثابت وقت الرتجمة ،مثل تعريفنا لـ :bufSize
يقوم املرتجم في العادة باستبدال استخدامات املتغري بقيمته املقابلة أثناء الرتجمة.
أي أن املرتجم سينئش كو ًدا باستخدام القيمة 512في األماكن اليت يستخدم فيها الكود .bufSize •
مهيِـئ املتغري .فعندما نقوم بتقسيم برنامج إلى عدة ملفات ،
ليستبدل املرتجم قيمة املتغري ،يجب عليه رؤية ّ
مهيِـئ الثابت.
يجب أن يكون لكل ملف يستخدم الثابت إمكانية الوصول إلى ّ •
املهيِـئ ،يجب تعريف املتغري في كل ملف يريد استخدام قيمة املتغري.
ّ ومن أجل رؤية •
لدعم االستخدام ،مع تجنب تعدد التعريفات للمتغري نفسه ،فإن متغرياتنا الثابتة يتم تعريفها محلية مللف. •
وعندما نعرف ثاب ًتا بنفس االسم في ملفات متعددة ، •
فسيبدو األمر كأننا كتبنا تعريفات ملتغريات منفصلة في كل ملف. •
لتعريف مثيل واحد من متغري ثابت ،نستخدم كلمة externفي كل من تعريفاتها وإعالناتها :
// file_1.cc defines and initializes const that accessible to other files
extern const int bufSize = fcn(); // file_1.h
;extern const int bufSize // same bufSize as defined in file_1.cc
ملحوظة
ملشاركة كائن ثابت بني ملفات متعددة ،يجب عليك تعريف املتغري على أنه خارجي .extern
التمرين :2.26
رشعيا ؟
ً -أي مما يلي يعترب
-بالنسبة لغري الرشعي ،ارشح السبب.
;(a) const int buf
;(b) int cnt = 0
;(c) const int sz = cnt
;(d) ++cnt; ++sz
2٫4٫1املراجع لثابت
2.4.1. References to const
ونظرًا ألنه ال يمكننا التعيني مبارشة على ، ciيجب أال نتمكن أيضاً من استخدام مرجع لتغيري .ci
لذلك ،فإن تهيئة r2خطأ .إن كانت هذه التهيئة رشعية ،فيمكننا استخدام r2لتغيري قيمة الكائن األسايس.
املرجع الثابت هو مرجع لثابت مصطلحات:
• يميل مربمجو يس ++إلى اختصار عبارة "مرجع لثابت "reference to const
• لتصبح "مرجعاً ثابتاً ."const Reference
• هذا االختصار منطقي -إن كنت تتذكر أنه اختصار.
فعلى وجه الخصوص ،يمكننا ربط مرجع لـثابت لكائن غري ثابت ،أو حرفي ،أو تعبري أكرث عمومية :
;int i = 42
;const int &r1 = i // we can bind const int& to plain int object
;const int &r2 = 42 // ok: r1 reference to const
;const int &r3 = r1 * 2 // ok: r3 reference to const
;int &r4 = r * 2 // error: r4 plain, non const reference
const int temp = dval; // create temporary const int from double
const int &ri = temp; // bind ri to that temporary
في هذه الحالة ri ،مرتبط بالكائن .temp •
الكائن tempكائن غري مسمى أنشأه املرتجم عندما احتاج إلى مكان لتخزين نتيجة من تقييم التعبري. •
غالبا ما يستخدم مربمجو يس ++كلمة tempكاختصار لكائن مؤقت.
ً •
فكر اآلن فيما يمكن أن يحدث إذا تم السماح بهذه التهيئة ولكن riلم تكن ثابتة.
إن لم تكن riثابتة ،فيمكننا التعيني على .ri •
سيؤدي القيام بذلك إلى تغيري الكائن الذي يرتبط به .ri •
لكن هذا الكائن هو ، tempوليس .dval •
من املحتمل أن يتوقع املربمج الذي جعل riيشري إلى dvalأن التعيني على riسيغري .dval •
بعد كل يشء ،ملاذا التعيني على riإال إذا كان القصد هو تغيري الكائن الذي يرتبط به ri؟ •
وألن ربط مرجع لـ tempليس بالتأكيد ما يقصده املربمج ،فإن اللغة تجعل الربط غري رشعي. •
من املهم أن ندرك أن املرجع للثابت يقيد فقط ما يمكننا القيام به من خالل ذلك املرجع.
إن ربط مرجع لـثابت إلى كائن ال يخرب شيًئ ا عن ما إذا كان الكائن األسايس نفسه ثاب ًتا. •
ونظرًا ألن الكائن األسايس قد يكون غري ثابت ،فقد يتم تغيريه بوسائل أخرى:
2٫4٫2املؤرشات والثابت
2.4.2. Pointers and const
كحال املراجع ،يمكننا تعريف مؤرشات تشري إلى أنواع ثابتة أو غري ثابتة.
ومثل املرجع لثابت ،ال يجوز استخدام مؤرش لثابت لتغيري كائن يشري إليه املؤرش. •
يجوز لنا تخزين عنوان كائن ثابت فقط في مؤرش لثابت:
;const double pi = 3.14 // pi const; its value may not be changed
;double *ptr = &pi // error: ptr plain pointer
const double *cptr = π // ok: cptr may point to double that is const
;*cptr = 42 // error: cannot assign to *cptr
;double dval = 3.14 // dval is a double; its value can be changed
;cptr = &dval // ok: but can't change dval through cptr
مثل املرجع لثابت ،ال يشري املؤرش لثابت إلى أي يشء حول ما إذا كان كائن يشري إليه املؤرش ثابتاً. •
يؤثر تحديد املؤرش كمؤرش لثابت على ما يمكننا فعله باملؤرش فقط. •
من املهم أن تتذكر أنه ال يوجد ضمان بأن كائناً يشري إليه مؤرش لثابت لن يتغري. •
تلميح
قد يكون مفيداً التفكري في مؤرشات ومراجع تشري لثابت كمؤرشات أو مراجع "تعتقد أنها ترجع أو تشري لثابت".
املؤرشات الثابتة
const Pointers
كما رأينا في الفقرة ، 2.3.3فإن أسهل طريقة لفهم هذه اإلعالنات هي قراءتها من اليمني إلى اليسار.
في هذه الحالة ،يكون الرمز األقرب إلى curErrهو ، constما يعين أن curErrبذاته ثابت. •
يتكون نوع ذلك الكائن من باقي املُعلن. •
الرمز التالي في املعلن هو * ،ما يعين أن curErrهو مؤرش ثابت. •
أخريًا ،يكمل نوع اﻹعالن األسايس نوع ، curErrمؤرش ثابت لكائن نوع عدد صحيح. •
وباملثل ،فإن pipعبارة عن مؤرش ثابت لكائن نوع مزدوج ثابت. •
حقيقة أن املؤرش هو نفسه ثابت ال يخرب شيًئ ا عما إذا كان بإمكاننا استخدام املؤرش لتغيري الكائن األسايس.
كليا على النوع الذي يشري إليه املؤرش.
تعتمد إمكانية تغيري هذا الكائن ً •
فعلى سبيل املثال pip ،هو مؤرش ثابت لثابت. •
فال يمكن تغيري قيمة كائن تتم معالجته بواسطة pipوال العنوان املخزن في .pip •
من ناحية أخرى ،يتعامل curErrمع عدد صحيح. •
التمرين :2.27
أي من عمليات التهيئة التالية تعترب رشعية؟ ارشح السبب.
;(a) int i = -1, &r = 0
;(b) int *const p2 = &i2
;(c) const int i = -1, &r = 0
;(d) const int *const p3 = &i2
;(e) const int *p1 = &i2
;(f) const int &const r2
;(g) const int i2 = i, &r = i
التمرين :2.28
ارشح التعاريف التالية .وحدد أي يشء غري رشعي.
;(a) int i, *const cp
;(b) int *p1, *const p2
;(c) const int ic, &r = ic
;(d) const int *const p3
;(e) const int *p
التمرين :2.29
باستخدام املتغريات في التمرين السابق ،أي من التعيينات التالية تعترب رشعية؟ ارشح السبب.
;(a) i = ic
;(b) p1 = p3
;(c) p1 = &ic
;(d) p3 = &ic
;(e) p2 = p1
;(f) ic = *p3
كما رأينا ،املؤرش عبارة عن كائن يمكن أن يشري إلى كائن مختلف.
نتيجة لذلك ،يمكننا التحدث بشكل مستقل حول ما إذا كان مؤرش ثاب ًتا ، •
وما إذا كانت الكائنات اليت يمكن أن يشري إليها ثابتة. •
نستخدم املصطلح ثابت املستوى العالي لنشري إلى أن املؤرش نفسه ثابت. •
عندما يمكن أن يشري مؤرش إلى كائن ثابت ،فإننا نشري إلى أن الثابت منخفض املستوى. •
بشكل عام ،يشري ثابت املستوى العالي إلى أن الكائن نفسه ثابت.
يمكن أن يظهر الثابت عالي املستوى في كائن من أي نوع. •
على سبيل املثال ،أحد األنواع الحسابية املدمجة أو نوع فئة أو نوع مؤرش. •
بينما يظهر الثابت منخفض املستوى في النوع األسايس لألنواع املركبة مثل املؤرشات أو املراجع. •
;int i = 0
int *const p1 = &i; // we can't change the value of p1; const is top-level
const int ci = 42; // we cannot change ci; const is top-level
;const int *p2 = &ci // we can change p2; const is low-level
const int *const p3 = p2; // right-most const is top-level, left-most not
const int &r ;= ci // const in reference types is always low-level
هذا التميزي بني املستوى العالي واملنخفض تظهر أهميته عندما نقوم بنسخ كائن.
فعندها ،يتم تجاهل ثوابت املستوى العالي:
;i = ci // ok: copying the value of ci; top-level const in ci is ignored
p2 = p3; // ok: pointed-to type matches; top-level const in p3 is ignored
ال يؤدي نسخ كائن إلى تغيري الكائن املنسوخ.
ولذا ،من غري املهم ما إذا كان املنسوخ منه أو املنسوخ إليه ثاب ًتا. •
من ناحية أخرى ،ال يتم تجاهل ثابت املستوى املنخفض أب ًدا. •
فعندما نقوم بنسخ كائن ،يجب أن يكون لكال الكائنني نفس مقيد الثابت منخفض املستوى ، •
أو يجب أن يكون هناك تحويل بني نوعي الكائنني. •
بشكل عام ،يمكننا تحويل غري الثابت إلى ثابت لكن ليس العكس:
التمرين :2.30
-بالنسبة إلى كل من التعريفات التالية ،
-حدد ما إذا كان الكائن الذي يتم اإلعالن به يحتوي على ثابت مستوى أعلى أم ثابت منخفض املستوى.
التمرين :2.31
-نظرًا لإلعالنات الواردة في التمرين السابق ،
-حدد ما إذا كانت التعيينات التالية رشعية أم ال.
-ارشح كيف يتم تطبيق ثابت املستوى األعلى أو املستوى املنخفض في كل حالة.
;r1 = v2
;p1 = p2 ;p2 = p1
;p1 = p3 ;p2 = p3
التعبري الثابت هو تعبري ال يمكن أن تتغري قيمته ويمكن تقييمه في وقت الرتجمة.
أيضا تعبرياً ثابتاً.
يعد الحرفي تعبرياً ثابتاً .كذلك يعد كائن ثابت تمت تهيئته من تعبري ثابت ً •
وكما سرنى ،هناك العديد من سياقات اللغة تتطلب تعبريات ثابتة. •
واملهيِـئات .فمثال:
ّ يعتمد كون كائن (أو تعبري) ما تعبرياً ثابتاً على األنواع
أفضل املمارسات
بشكل عام ،من الجيد استخدام constexprللمتغريات اليت تنوي استخدامها كتعبريات ثابتة.
اﻷنواع الحرفية
Literal Types
نظرًا ألن التعبري الثابت هو تعبري يمكن تقييمه في وقت الرتجمة ،
• فهناك حدود لألنواع اليت يمكننا استخدامها في إعالن تعبري-ثابت.
تُعرف األنواع اليت يمكننا استخدامها في التعبري الثابت باسم "األنواع الحرفية" •
ألنها بسيطة بما يكفي للحصول على قيمة حرفية. •
أنواعا حرفية.
ً من بني األنواع اليت استخدمناها حىت اآلن ،تعد أنواع الحسابات واملراجع واملؤرشات
فئة عنرص املبيعات ومكتبة املدخالت واملخرجات وأنواع السالسل ليست أنواعا حرفية. •
ومن ثم ،ال يمكننا تعريف متغريات من هذه األنواع كتعبريات-ثابتة. •
أنواعا أخرى من األنواع الحرفية في 7.5.6و .19.3
ً سرنى •
ألسباب سنغطيها في الفقرة ، 6.1.1ال يتم عاد ًة تخزين املتغريات املعرفة داخل دالة في عنوان ثابت.
ومن ثم ،ال يمكننا استخدام مؤرش تعبري-ثابت لإلشارة إلى مثل هذه املتغريات. •
من ناحية أخرى ،فإن عنوان الكائن املعرف خارج أي دالة هو تعبري ثابت ، •
وبالتالي يمكن استخدامه لتهيئة مؤرش تعبري-ثابت. •
نعرف مؤرشًا في إعالن تعبري ثابت ،فإن معرف التعبري-الثابت ينطبق على املؤرش ،
من املهم أن نفهم أنه عندما ّ
وليس النوع الذي يشري إليه :
constexpr int *np = nullptr; //np constant pointer to int that is null
;int j = 0
;constexpr int i = 42 // type of i is const int
// i and j must be defined outside any function
constexpr const int *p = &i; // p constant pointer to const int i
;constexpr int *p1 = &j // p1 constant pointer to int j
التمرين :2.32
-هل الكود التالي رشعي أم ال؟
-إذا لم يكن كذلك ،كيف يمكنك جعله رشعيا؟
;int null = 0, *p = null
. 2٫5التعــــــــــامل مــــــــــع اﻷنــــــــــواع
أيضا.
مع زيادة تعقيد برامجنا ،سرنى أن األنواع اليت نستخدمها تزداد تعقي ًدا ً
تنشأ التعقيدات في استخدام األنواع بطريقتني مختلفتني. •
فبعض األنواع يصعب "تهجئتها" .أي أن لديها أشكااًل مملة وعرضة للخطأ في الكتابة. •
وعالوة على ذلك ،يمكن أن يحجب شكل النوع املعقد غرضه أو معناه. •
أما املصدر اآلخر للتعقيدات فهو أنه أحياناً يصعب تحديد النوع الدقيق الذي نحتاجه. •
حيث قد يتطلب القيام بذلك النظر للوراء إلى سياق الربنامج. •
قد تظهر كلمة تعريف-النوع typedefاألساسية كجزء من إعالن النوع األسايس. •
تعرف أسماء النوع املستعارة بدال ً من املتغريات.
اﻹعالنات اليت تتضمن تعريف-النوع ّ •
وكحال أي إعالن آخر ، •
يمكن للمعلنات تضمني ُم ِّ
عدالت نوع تعرف أنواعاً مركبة مبنية من تعريفات النوع األساسية. •
الطريقة الثانية لتعريف نوع االسم املستعار قُدمت باملعيار الجديد ،عرب إعالن االسم املستعار :
يبدأ تعريف االسم املستعار بكلمة usingاألساسية متبوعة باالسم املستعار ثم =. •
يعرف إعالن االسم املستعار االسم على الجهة اليرسى من = كاسم مستعار للنوع الظاهر على الجهة اليمىن.
ّ •
نوع االسم املستعار عبارة عن اسم نوع ويمكن أن يظهر في أي مكان يحتمل أن يظهر فيه اسم نوع:
قد يكون من املغري -وإن كان غري صحيح -تفسري إعالن يستخدم اسم نوع مستعار
وذلك باستبدال االسم املستعار بنوعه املقابل من ناحية املفاهيم : •
مهيِـئ :
بشكل ضمين ،يجب على متغري يستخدم autoكمحدد نوعه أن يكون له ّ
//type of item deduced from type of result of adding val1 and val2
auto item = val1 + val2; // item initialized to result of val1 + val2
هنا سوف يستنتج املرتجم نوع itemمن النوع املعاد من تطبيق +على val1و .val2 •
فإن كانت val1و val2كائنات عنرص املبيعات ،فسيكون نوع itemعنرص مبيعات. •
وإن كانت هاتان املتغريتان من نوع املزدوج ، doubleفهذا يعين أن itemنوعها مزدوج ،وهكذا. •
وكحال أي محدد نوع آخر ،يمكننا تحديد متغريات متعددة باستخدام .auto •
auto i ;= 0, *p = &i // ok: i int and p pointer to int
;auto sz = 0, pi = 3.14 // error: inconsistent types for sz and pi
املهيِـئ.
النوع الذي يستنتجه املرتجم للنوع التلقائي ليس دوماً هو نفسه نوع ّ
فأحياناً ،يقوم املرتجم بتعديل النوع ليتوافق مع قواعد التهيئة العادية. •
مرجعا ،فإننا بالفعل نستخدم الكائن الذي يشري إليه املرجع.
ً أوال ً ،وكما رأينا ،عندما نستخدم •
املهيِـئ هو الكائن املقابل.
ّ كمهيِـئ ،فإن
ّ مرجعا
ً وعلى وجه الخصوص ،عندما نستخدم •
إذا أردنا أن يكون للنوع املستنتج قيمة ثابتة عال املستوى ،يجب أن نقول ذلك بشكل رصيح :
const auto f = ci; // deduced type of ci is int; f has type const int
املهيِـئ.
ّ مرجعا لنوع ُمستنتج تلقائياً ،ال يتم تجاهل ثوابت املستوى العالي في
ً عندما نطلب
مرجعا بمهيـئ.
ً كالعادة ،ال تكون الثوابت عالية املستوى عندما نربط •
تلقائيا :
ً أنواعا متسقة يتم استنتاجها
ً املهيِـئات
كالعادة ،يجب أن توفر ّ
التمرين :2.33
-باستخدام تعريفات املتغريات من هذا القسم ،حدد ما يحدث في كل من هذه التعيينات:
تمرين :2.35
-حدد األنواع املستخلصة في كل من التعريفات التالية.
برنامجا لرتى ما إذا كنت على صواب.
ً -بمجرد معرفة األنواع ،اكتب
;const int i = 42
;auto j = i; const auto &k = i; auto *p = &i
;const auto j2 = i, &k2 = i
أحياناً نريد تعريف متغري بنوع يستنتجه املرتجم من تعبري ما لكننا ال نريد استخدام ذلك التعبري لتهيئة املتغري.
بالنسبة ملثل هذه الحاالت ،قدم املعيار الجديد محد ًدا من نوع ثان ،هو النوع-املعلن ، decltype •
والذي يعيد نوع معامله .حيث يحلل املرتجم التعبري لتحديد نوعه لكنه ال يقيم التعبري : •
هنا ،ال يستدعي املرتجم ، fلكنه يستخدم النوع الذي سيعيده مثل ذلك االستدعاء كنوع لـ . sum •
أي أن املرتجم يعطي sumنفس النوع الذي سيعاد إذا استدعينا .f •
تختلف طريقة تعامل النوع-املعلن decltypeمع الثابت عالي املستوى واملراجع اختال ًفا طفي ًفا ، •
عن طريقة النوع التلقائي .auto •
فعندما يكون التعبري الذي نطبق عليه النوع-املعلن متغريًا ، •
يعيد النوع-املعلن نوع ذلك املتغري ،بما في ذلك ثابت املستوى العالي واملراجع : •
وألن cjعبارة عن مرجع ،فإن) decltype(cjنوع مرجعي .ومثل أي مرجع آخر ،يجب تهيئة .z
تجدر اإلشارة إلى :
عرف كمرجع ﻻ يتم التعامل معه كمرادف لكائن يشري إليه.
أن النوع-املعلن هو السياق الوحيد حيث متغري يُ ّ
النوع-املعلن واملراجع
decltype and References
عندما نطبق النوع-املعلن على تعبري ليس متغريًا ،نحصل على النوع الذي ينتج عن ذلك التعبري.
مرجعيا.
ً نوعا
• كما سرنى في الفقرة ، 4.1.1ستنتج بعض تعبريات النوع-املعلن ً
مرجعيا لتعبريات تنتج كائنات يمكن أن تكون على الجانب األيرس من التعيني:
ً نوعا
بشكل عام ،يعيد النوع-املعلن ً
مرجعا له.
ً من ناحية أخرى ،فإن عامل إلغاء املرجع هو مثال للتعبري الذي يعيد النوع-املعلن •
كما رأينا ،عندما نلغي مرجعاً عن مؤرش ،نحصل على الكائن الذي يشري إليه املؤرش. •
عالوة على ذلك ،يمكننا تعيني ذلك الكائن. •
بالتالي ،فإن النوع املستنتج من ) decltype(*pهو عدد صحيح مرجعي وليس عدداً صحيحاً فحسب. •
التمرين :2.36
في الكود التالي ،حدد نوع كل متغري وقيمة كل متغري عند انتهاء الكود:
;int a = 3, b = 4
;decltype(a) c = a
;decltype((b)) d = a
;++c
;++d
التمرين :2.37
-التعيني هو مثال على تعبري ينتج عنه نوع مرجع.
-النوع هو إشارة إلى نوع املعامل األيرس.
-بمعىن ،إذا كانت iعبارة عن ، intفإن نوع التعبري i = xهو .& int
-باستخدام هذه املعرفة ،حدد نوع وقيمة كل متغري في هذا الكود:
;int a = 3, b = 4
;decltype(a) c = a
;decltype(a = b) d = a
التمرين :2.38
ِ -
صف االختالفات في استنتاجات النوع بني النوع-املعلن والنوع التلقائي decltypeو.auto
أنواعا مختلفة.
ً -أعط مثاال ً لتعبري يستنتج " "autoو " "decltypeنوع واحداً ومثاال ً حيث يستنتجان
.2٫6تعــــــــــريف هيــــــــــاكل بيانــــــــــاتنا
2.6. Defining Our Own Data Structures
بالرغم من أننا ال نستطيع حىت اآلن كتابة فئتنا عنرص املبيعات ،
إال أنه يمكننا كتابة فئة أكرث واقعية تضم نفس عنارص البيانات. •
اسرتاتيجيتنا في استخدام هذه الفئة هي : •
أن املستخدمني سيستطيعون الوصول إلى عنارص بيانات مبارشة ، •
ويجب عليهم تنفيذ العمليات املطلوبة ألنفسهم. •
ونظرًا ألن هيكلة بياناتنا ال تدعم أي عمليات ، •
فسنقوم بتسمية نسختنا بيانات املبيعات Sales_dataلتميزيها عن عنرص املبيعات. •
{ struct Sales_data
;std::string bookNo
;unsigned units_sold = 0
;double revenue = 0.0
;}
تبدأ فئتنا بكلمة structاألساسية ،متبوع ًة باسم الفئة وبنيتها (قد تكون فارغ ًة). •
بنية الفئة تحاط بأقواس معقوفة وتشكل نطا ًقا جدي ًدا. •
يجب أن تكون األسماء املعرفة داخل الفئة فريدة داخلها لكن يمكن إعادة استخدام األسماء املعرفة خارجها. •
يجب أن يتبع القوس املجعد املغلق الذي ينهي بنية الفئة فاصلة منقوطة. •
الفاصلة املنقوطة مطلوبة ألنه يمكننا من تعريف متغريات بعد بنية الفئة : •
تشري الفاصلة املنقوطة إلى نهاية قائمة اإلعالنات (الفارغة عاد ًة). •
في العادة ،من الجيد تعريف كائن كجزء من تعريف الفئة. •
يؤدي القيام بذلك إلى حجب الكود •
وذلك عن طريق دمج تعريفات كيانني مختلفني -الفئة واملتغري -في جملة واحدة. •
تحذير
من الخطأ الشائع بني املربمجني الجدد نسيان الفاصلة املنقوطة في نهاية تعريف الفئة.
نعرف أعضاء البيانات بنفس الطريقة اليت نعرف بها املتغريات العادية :
معرفات واحد أو أكرث.
متبوعا بقائمة من ّ
ً أساسيا
ً نوعا
نعرف ً •
تتكون فئتنا من ثالثة أعضاء بيانات : •
عضو نوع سلسلة stringيُسمى رقم-الكتاب ، bookNo •
وعضو عدد صحيح بال_إشارة يُسمى وحدات_مباعة ، unit_sold •
وعضو نوع مزدوج عرشي يسمى إيرادات .revenue •
سيحتوي كل كائن بيانات مبيعات Sales_dataعلى أعضاء البيانات الثالثة هذه. •
التمرين :2.39
-قم برتجمة الربنامج التالي ملعرفة ما يحدث عندما تنىس الفاصلة املنقوطة بعد تعريف فئة.
-تذكر الرسالة للرجوع إليها في املستقبل.
فعلى سبيل املثال ،سنكتب نسخة من الربنامج من الفقرة 1٫5٫2واليت طبعت مجموع معاملتني.
ستكون املدخالت في برنامجنا عبارة عن معامالت مثل •
0-201-78345-X 3 20.00.0000
0-201-78345-X 2 25.00.0000
كل معاملة ستحمل رقم الردمك ،وعدد الكتب املباعة ،والسعر الذي تم بيع كل كتاب به.
>#include <iostream
>#include <string
"#include "Sales_data.h
)(int main
{
;Sales_data data1, data2
// code to read into data1 and data2
// code to check whether data1 and data2 have same ISBN
// and if so print sum of data1 and data2
}
كما في برنامجنا األصلي ،نبدأ بتضمني العناوين اليت سنحتاجها وتعريف املتغريات لتحمل املدخالت. •
الحظ أنه بخالف نسخة عنرص املبيعات ،يتضمن برنامجنا الجديد عنوان السلسلة .string •
نحتاج إلى هذا العنوان ألن كودنا سيتعني عليه إدارة عضو رقم-الكتاب ،والذي نوعه سلسلة. •
بالرغم من أننا لن نصف نوع مكتبة السلسلة بالتفصيل حىت الفصلني 3و ، 10
إال أننا نحتاج إلى معرفة القليل فقط عنها من أجل تعريف واستخدام العضو .ISBN •
نوع السلسلة يحمل سلسلة من األحرف. •
، == تتضمن عملياتها عوامل مدخالت ومخرجات << >> وتساوي •
. على التوالي، وذلك لقراءة السالسل وكتابتها ومقارنتها •
.تحتوي معامالتنا على السعر الذي تم بيع كل كتاب به لكن هيكل بياناتنا يخزن إجمالي اإليرادات
: جملة املدخالت.revenue والذي سنحسب منه عضو اإليرادات، price سنقرأ بيانات املعاملة إلى املزدوج
:data2 سيقوم برنامجنا بعد ذلك بتكرار نفس الكود لقراءة البيانات إلى
: وإال فسنطبع رسالة خطأ، مهمتنا األخرى هي التحقق من أن املعامالت هي لنفس رقم الردمك
if (data1.bookNo == data2.bookNo) {
unsigned totalCnt = data1.units_sold + data2.units_sold;
double totalRevenue = data1.revenue + data2.revenue;
// print: ISBN, total sold, total revenue, average price per book
std::cout << data1.bookNo << " " << totalCnt
<< " " << totalRevenue << " ";
if (totalCnt != 0)
;std::cout << totalRevenue/totalCnt << std::endl
else
;std::cout << "(no sales)" << std::endl
;return 0 // indicate success
{ } else // transactions weren't for the same ISBN
std::cerr ;<< "Data must refer to the same ISBN" << std::endl
;return -1 // indicate failure
}
في ifاألولى قمنا بمقارنة العضو رقم الكتاب في كل من data1و .data2 •
فإن كان لهما نفس رقم الردمك ،فإننا ننفذ الكود داخل األقواس املتعرجة. •
يضيف الكود مكونات املتغريين لدينا. •
وألننا سنحتاج إلى طباعة متوسط السعر ، •
نبدأ بحساب إجمالي الوحدات املباعة واإليرادات •
وتخزينها في إجمالي العدد totalCntوإجمالي اإليرادات totalRevenueعلى التوالي. •
نطبع تلك القيم. •
بعد ذلك نتحقق من بيع الكتب ،فإذا وجدت مبيعات ،سنقوم بطباعة متوسط السعر املحسوب لكل كتاب. •
إذا لم تكن هناك مبيعات ،نطبع رسالة تشري إلى هذه الحقيقة. •
التمرين :2.41
-استخدم فئة Sales_dataإلعادة كتابة التدريبات الواردة في ، 1.5.1و ، 1.5.2و 1.6
-في الوقت الحالي ،يجب عليك تعريف فئتك Sales_dataفي نفس امللف مثل دالتك . main
بالرغم من أننا سرنى في الفقرة ، 19.7كيف يمكننا تعريف فئة داخل دالة ،فإن هذه الفئات لها دوال محدودة.
نتيجة لذلك ،ال يتم تعريف الفئات عاد ًة داخل الدوال. •
عندما نعرف فئة خارج دالة ،قد يكون هناك تعريف واحد فقط لتلك الفئة في أي ملف مصدر معني. •
إضافة إلى ذلك ،إذا استخدمنا فئة في عدة ملفات مختلفة ، •
فيجب أن يكون تعريف الفئة هي نفسها في كل ملف. •
تحتوي العناوين (عاد ًة ) على كيانات (مثل تعريفات فئات ومتغريات لثوابت ولتعبريات ثابتة) ، •
يمكن تعريفها مرة واحدة فقط في أي ملف معني .مع ذلك ، •
غالبا ما تحتاج العناوين إلى استخدام أقسام من عناوين أخرى.
ً •
مثالً ،نظرًا ألن فئتنا بيانات املبيعات بها عضو سلسلة ، •
يجب أن يقوم العنوان Sales_data.hبتضمني عنوان السلسلة. •
أيضا إلى تضمني عنوان السلسلة،
كما رأينا ،تحتاج الربامج اليت تستخدم بيانات املبيعات ً •
وذلك من أجل استخدام عضو رقم الكتاب. •
نتيجة لذلك ،ستتضمن الربامج اليت تستخدم بيانات املبيعات عنوان السلسلة مرتني : •
مرة مبارشة ومرة كأثر جانيب لتضمني .Sales_data.h •
ونظرًا ألنه قد يتم تضمني العنوان أكرث من مرة ، •
سنحتاج إلى كتابة عناويننا بطرق آمنة حىت لو تم تضمني العنوان عدة مرات. •
ملحوظة
عندما يتم تحديث عنوان ،يجب إعادة تجميع امللفات املصدر اليت تستخدم ذلك العنوان
ﻷخذ اإلعالنات الجديدة أو املتغرية.
شيوعا لجعل تضمني عنوان ما عدة مرات آمنًا يعتمد على املعالج اﻷولي. PreProcessor
ً األسلوب األكرث
املعالج اﻷولي -والذي ورثته يس ++من يس -برنامج يعمل قبل املرتجم ويغري النص املصدر لربامجنا. •
تعتمد برامجنا بالفعل على أحد أقسام املعالج اﻷولي. #include : •
فعندما يرى ، #includeفإنه يستبدلها بمحتويات العنوان املحدد. •
يمكننا استخدام هذه اﻷقسام للحماية من التضمني املتعدد على النحو التالي:
#ifndef SALES_DATA_H
#define SALES_DATA_H
>#include <string
{ struct Sales_data
;std::string bookNo
;unsigned units_sold = 0
;double revenue = 0.0
;}
#endif
في املرة األولى اليت يتم فيها تضمني ، Sales_data.hسينجح اختبار .#ifndef •
وسيقوم املعالج األولي بمعالجة األسطر التالية لـ #ifndefحىت .#endif •
ونتيجة لذلك ،سيتم تعريف متغري املعالج اﻷولي SALES_DATA_H •
وسيتم نسخ محتويات Sales_data.hفي برنامجنا. •
فإن قمنا بتضمني Sales_data.hالح ًقا في نفس امللف ،فسيكون التوجيه #ifndefخاطًئ ا. •
وسيتم تجاهل األسطر املوجودة بينه وبني األمر .#endif •
تحذير
ال تحرتم أسماء متغريات املعالج اﻷولي قواعد تحديد النطاق لـ يس.++
أفضل املمارسات
ينبغي أن تحتوي العناوين على حراسة ،حىت لو لم يتم تضمينها (بعد) في عنوان آخر. •
تافها ،ومن خالل تعريفها بشكل اعتيادي ،
ً تعترب كتابة حارسات العناوين أمرًا •
فلن تحتاج إلى تحديد ما إذا كانت هناك حاجة إليها أم ال. •
Chapter Summary
يعرف كل نوع متطلبات التخزين والعمليات اليت يمكن إجراؤها على كائنات ذلك النوع.
توفر اللغة مجموعة من األنواع األساسية املدمجة مثل العدد الصحيح intوالحرف ، char •
ارتباطا وثي ًقا بتمثيلها على أجهزة الجهاز.
ً واليت ترتبط •
Defined Terms
أنواع حسابية أنواع مدمجة تمثل القيم املنطقية واألحرف واألعداد الصحيحة وأرقام
arithmetic types
النقطة العائمة العرشية.
مصفوفة :بنية بيانات تحتوي على مجموعة من الكائنات غري املسماة اليت يتم
array
الوصول إليها بواسطة فهرس .يغطي الفصل 5املصفوفات بالتفصيل.
auto مهيِـئه.
محدد نوع تلقائي يستنتج نوع املتغري من ّ
نوع أسايس :محدد نوع ربما مقيد بواسطة ثابت ،يسبق املعلنات في إعالن.
base type
يوفر النوع األسايس النوع الشائع الذي يمكن للمعلنات البناء عليه في إعالن.
إقران :إقران اسم بكيان معني بحيث تكون استخدامات االسم استخدامات للكيان
bind
األسايس .مثال يعد املرجع اسماً مقرتن بكائن.
byte بايت :أصغر وحدة ذاكرة قابلة للعنونة .في معظم األجهزة ،يكون البايت 8بت.
compound type نوع مركب :نوع معرف برشوط ومصطلحات نوع آخر.
ثابت :مقيد نوع يُستخدم لتعريف كائنات ال يمكن تغيري قيمتها .يجب تهيئة أي كائن
const
ثابت ،ألنه ال توجد طريقة ملنحها قيمة بعد تعريفها.
constexpr تعبري-ثابت :متغري يمثل تعبريًا ثاب ًتا .يشمل دوال تعبري-ثابت.
تحويل :عملية يتم فيها تحويل قيمة نوع لقيمة نوع آخر .تعرف اللغة تحويالت بني
conversion
األنواع املدمجة.
عضو بيانات :عنارص بيانات تشكل كائنًا .كل كائن فئة معينة له نسخته الخاصة من
data member
أعضاء بيانات الفئة .يمكن تهيئة أعضاء البيانات عند اإلعالن عنها داخل الفئة.
إعالن :توكيد لوجود متغري أو دالة أو نوع معرف في مكان آخر .ال يجوز استخدام
declaration
األسماء حىت يتم تعريفها أو اإلعالن عنها.
مهيِـئا رصيحا.
تهيئة افرتاضية :كيفية تهيئة الكائنات عند عدم إعطاءها ّ
تتحكم الفئة في كيفية تهيئة كائنات نوعها.
default initialization
يتم تهيئة كائنات النوع املدمج املعرف في النطاق العام على 0؛
بينما تلك املعرفة على النطاق املحلي تكون غري مهيأة ولها قيم غري معرفة.
global scope نطاق عام :نطاق يقع خارج جميع النطاقات األخرى.
حارس العنوان :متغري معالج أولي يستخدم ملنع تضمني العنوان أكرث من مرة في
header guard
ملف واحد.
identifier معرف :تسلسل أحرف تشكل االسم .املعرفات حساسة لحالة األحرف.
ّ
initialized تمت التهيئة :متغري يعطى قيمة أولية عند تعريفه .يجب تهيئة املتغريات عادة.
inner scope نطاق داخلي :النطاق الداخلي املتداخل داخل نطاق آخر.
الحرفي :قيمة مثل رقم أو حرف أو سلسلة من األحرف .ال يمكن تغيري القيمة.
literal يتم تضمني األحرف الحرفية في عالمات اقتباس مفردة ،
بينما يتم وضع السالسل الحرفية في عالميت اقتباس مزدوجتني.
local scope نطاق محلي :مرادف عام لنطاق الكتلة.
null pointer مؤرش خالي :مؤرش قيمته .0املؤرش الخالي صالح لكنه ال يشري إلى أي كائن.
pointer مؤرش :كائن يمكنه االحتفاظ بعنوان كائن أو عنوان ما بعد نهاية كائن أو صفر.
preprocessor معالج أولي :برنامج معالج يعمل كجزء من تجميع برنامج يس.++
separate compilation التجميع املنفصل :القدرة على تقسيم الربنامج إلى عدة ملفات مصدر منفصلة.
مؤقت :كائن غري مسمى تم إنشاؤه بواسطة املرتجم أثناء تقييم تعبري.
temporary
يتواجد املؤقت حىت نهاية أكرب تعبري يحيط بالتعبري الذي تم إنشاؤه من أجله.
top-level const ثابت املستوى العالي :ثابت يحدد بأنه ال يمكن تغيري كائن.
نوع مستعار :اسم مستعار لنوع آخر .يتم تعريفه من خالل إما تعريف-نوع أو إعالن
type alias
اسم مستعار.
فحص نوع :مصطلح يستخدم لوصف العملية اليت يتحقق من خاللها املرتجم من أن
type checking
الطريقة اليت يتم بها استخدام كائنات من نوع معني تتفق مع تعريف هذا النوع.
معرف :استخدام ال تحدد اللغة معىن له .يعد االعتماد عن قصد أو بالخطأ على
غري ّ
undefined مصدرا غنياً ألخطاء وقت تشغيل يصعب تتبعها وملشكالت األمان
ً معرف غري سلوك
وقابلية النقل.
بال_إشارة :نوع عدد صحيح بال_إشارة يحتوي فقط على قيم أكرب من أو تساوي
unsigned
الصفر.
كلمة :الوحدة الطبيعية لحوسبة عدد صحيح على آلة معينة .عادة ما تكون الكلمة
word
كبرية بما يكفي لتحتفظ بعنوان .على جهاز 32بت ،تتكون الكلمة عاد ًة من 4بايت.
& operator عامل العنوان .يعطي عنوان الكائن الذي يتم تطبيقه عليه.
عامل إلغاء املرجع .يؤدي إلغاء مرجع عن مؤرش إلى إعادة الكائن الذي يشري إليه
* operator
املؤرش .يؤدي التعيني إلى نتيجة مرجع مزال إلى تعيني قيمة جديدة للكائن األسايس.
# define توجيه املعالج اﻷولي الذي يعرف متغري املعالج اﻷولي.
# endif توجيه املعالج اﻷولي الذي ينهي منطقة ifdef#أو .ifndef#
# ifdef توجيه املعالج اﻷولي الذي يحدد ما إذا كان متغريًا معرفاً أم ال.
# ifndef توجيه املعالج اﻷولي الذي يحدد ما إذا لم يتم تعريف متغري معني.