You are on page 1of 81

‫الجــــــــــزء اﻷول ‪ :‬اﻷســــاسيـــــــات‬

‫‪Part I: The Basics‬‬

‫الـمحتويات‬
‫‪Contents‬‬

‫‪Chapter 2‬‬ ‫الفصل ‪2‬‬

‫‪Variables and Basic Types‬‬ ‫املتغريات واﻷنواع اﻷساسية‬

‫‪Chapter 3‬‬ ‫الفصل ‪3‬‬

‫‪Strings, Vectors, and Arrays‬‬ ‫السالسل‪ ،‬املتجهات واملصفوفات‬

‫‪Chapter 4‬‬ ‫الفصل ‪4‬‬

‫‪Expressions‬‬ ‫التعبيـــــــــــرات‬

‫‪Chapter 5‬‬ ‫الفصل ‪5‬‬

‫‪Statements‬‬ ‫الجمــــــــــل‬

‫‪Chapter 6‬‬ ‫الفصل ‪6‬‬

‫‪Functions‬‬ ‫الـــــــــــدوال‬

‫‪Chapter 7‬‬ ‫الفصل ‪7‬‬

‫‪Classes‬‬ ‫الفئــــــــــات‬
‫توفر كل لغة برمجة مستخدمة على نطاق واسع مجموعة مشرتكة من املزيات ‪،‬‬
‫تختلف تفاصيلها من لغة إلى أخرى‪.‬‬ ‫•‬
‫إن فهم تفاصيل كيفية توفري اللغة لهذه املزيات هي أول خطوة نحو فهم اللغة‪.‬‬ ‫•‬

‫من بني أهم تلك السمات املشرتكة أنواع مدمجة مثل األعداد الصحيحة واألحرف وما إلى ذلك ‪،‬‬ ‫•‬
‫متغريات ‪ ،‬تتيح لنا منح أسماء لكائنات نستخدمها ‪،‬‬ ‫•‬
‫تعبريات وجمل تعالج قيم هذه األنواع ‪،‬‬ ‫•‬
‫بنية تحكم ‪ ،‬مثل إذا_ ‪ if‬أو طالـما_ ‪ ،while‬تسمح لنا بتنفيذ مجموعة إجراءات بشكل متكرر أو مرشوط‬ ‫•‬
‫دوال تسمح لنا بتعريف وحدات حوسبة قابلة لالستدعاء‬ ‫•‬

‫تكمل معظم لغات الربمجة هذه املزيات األساسية بطريقتني‪:‬‬


‫فإما أن تسمح للمربمجني بتوسيع اللغة عن طريق تعريف أنواعهم الخاصة ‪،‬‬ ‫•‬
‫تعرف دواال ً وأنواعاً مفيدة لم يتم دمجها في اللغة بطريقة أخرى‪.‬‬
‫وإما أن توفر إجراءات مكتبة ّ‬ ‫•‬

‫يعرف نوع الكائن العمليات اليت يمكن إجراؤها عليه‪.‬‬


‫في يس‪ ، ++‬كما في معظم لغات الربمجة ‪ّ ،‬‬ ‫•‬
‫يعتمد كون تعبري معني رشعيا على نوع الكائنات في ذلك التعبري‪.‬‬ ‫•‬
‫فبعض اللغات ‪ ،‬مثل ‪ Smalltalk‬و ‪ ، Python‬تفحص األنواع في وقت التشغيل‪.‬‬ ‫•‬
‫في املقابل ‪ ،‬يس‪ ++‬هي لغة مكتوبة بشكل ثابت ؛ حيث يتم فحص النوع في وقت الرتجمة‪.‬‬ ‫•‬
‫ونتيجة لذلك ‪ ،‬يجب أن يعرف املرتجم نوع كل اسم مستخدم في الربنامج‪.‬‬ ‫•‬

‫تتوفر في يس ‪ ، ++‬مجموعة من األنواع املدمجة ‪ ،‬وعوامل للتعامل معها ‪،‬‬ ‫•‬


‫ومجموعة صغرية من جمل التحكم في تدفق الربنامج‪.‬‬ ‫•‬
‫تمكننا من كتابة أنظمة واقعية كبرية ومعقدة‪.‬‬
‫تشكل تلك العنارص أبجدية ّ‬ ‫•‬
‫في هذا املستوى األسايس ‪ ،‬تعد يس‪ ++‬لغة بسيطة‪.‬‬ ‫•‬
‫حيث تنبع قوتها التعبريية من دعمها آلليات تسمح للمربمج تعريف هياكل بيانات جديدة‪.‬‬ ‫•‬
‫وباستخدام هذه اﻷقسام ‪،‬‬ ‫•‬
‫يمكن للمربمجني تشكيل اللغة ألهدافهم دون أن يضطر مصممو اللغة إلى توقع احتياجات مربمجيها‪.‬‬ ‫•‬

‫قد تكون الفئات أهم مزية في يس‪ ، ++‬واليت تتيح للمربمجني تعريف أنواعهم الخاصة‪.‬‬ ‫•‬
‫في يس‪ ، ++‬يطلق على هذه األنواع أحيا ًنا "أنواع الفئات" لتميزيها عن األنواع املدمجة في اللغة‪.‬‬ ‫•‬
‫تسمح بعض اللغات للمربمجني بتعريف أنواع تحدد فقط بيانات يتكون منها النوع‪.‬‬ ‫•‬
‫تسمح بعضها اآلخر ‪ ،‬مثل يس‪ ، ++‬للمربمجني تعريف أنواع تتضمن العمليات وكذلك البيانات‪.‬‬ ‫•‬
‫يتمثل أحد أهداف التصميم الرئيسية لـ يس‪، ++‬‬ ‫•‬
‫في السماح للمربمجني بتعريف أنواعهم الخاصة اليت يسهل استخدامها مثل األنواع املدمجة‪.‬‬ ‫•‬
‫تستخدم مكتبة اليس‪ ++‬القياسية هذه املزيات لتنفيذ مكتبة غنية ألنواع الفئات والدوال املرتبطة بها‪.‬‬ ‫•‬
‫أول خطوة في إتقان يس‪ ++‬هي مواضيع الجزء األول‪ -‬تعلم أساسيات اللغة واملكتبة ‪.-‬‬
‫حيث يغطي الفصل الثاني األنواع املدمجة وينظر بإيجاز في آليات تعريف أنواعنا الجديدة‪.‬‬ ‫•‬
‫يقدم الفصل الثالث نوعني من أنواع املكتبات األساسية‪ :‬السلسلة ‪ string‬واملتجه ‪.vector‬‬ ‫•‬
‫أيضا املصفوفات ‪،array‬‬
‫يغطي ذلك الفصل ً‬ ‫•‬
‫وهي بنية بيانات منخفضة املستوى مدمجة في يس‪ ++‬وعدة لغات أخرى‪.‬‬ ‫•‬
‫تغطي الفصول من الرابع إلى السادس التعبريات والجمل والدوال‪.‬‬ ‫•‬
‫يختتم هذا الجزء بالفصل السابع ‪ ،‬الذي يصف أساسيات بناء أنواع فئاتنا‪.‬‬ ‫•‬
‫كما سرنى ‪ ،‬فإن تعريف أنواعنا الخاصة يجمع كل ما تعلمناه من قبل ‪،‬‬ ‫•‬
‫وذلك ألن كتابة فئة ما يستلزم استخدام األقسام املشمولة في الجزء األول‪.‬‬ ‫•‬
‫الفصــــــــــل ‪ . 2‬املتغيــــــــــرات واﻷنــــــــــواع اﻷساسيــــــــــة‬

‫‪Chapter 2. Variables and Basic Types‬‬

‫الـمحتويات‬
‫‪Contents‬‬

‫‪2.1 Primitive Built-in Types‬‬ ‫‪ 2٫1‬اﻷنــــــواع املدمجة اﻷوليــــــة‬

‫‪2.2 Variables‬‬ ‫‪ 2٫2‬املتغيــــــرات‬

‫‪2.3 Compound Types‬‬ ‫‪ 2٫3‬اﻷنــــــواع املركبــــــة‬

‫‪2.4 const Qualifier‬‬ ‫‪ 2٫4‬املقيـــد ‪ :‬الثابــــــت‬

‫‪2.5 Dealing with Types‬‬ ‫‪ 2٫5‬التعــــــامل مع اﻷنـــــــواع‬

‫‪2.6 Defining Our Own Data Structures‬‬ ‫‪ 2٫6‬تعريــــــف هياكــل بيانــــــاتنا‬

‫‪Chapter Summary‬‬ ‫مــلـــخــــــص الــفــصــــــل‬

‫‪Defined Terms‬‬ ‫مصطلحــــــات معرفــــــة‬

‫األنواع أساسية ألي برنامج‪ :‬فهي تخربنا بما تعنيه بياناتنا والعمليات اليت يمكننا إجراؤها على تلك البيانات‪.‬‬

‫تعرف عدة أنواع بدائية ‪،‬‬


‫يحتوي يس‪ ++‬على دعم واسع لألنواع‪ .‬فاللغة ّ‬
‫• ( كاألحرف ‪ ،‬واألعداد الصحيحة ‪ ،‬وكذلك أرقام الفاصلة العائمة ‪ ،‬وما إلى ذلك)‪.‬‬

‫كذلك توفر اللغة آليات تتيح لنا تعريف أنواع بيانات خاصة بنا‪.‬‬
‫تستخدم املكتبة هذه اآلليات لتعريف أنواع أكرث تعقي ًدا ‪،‬‬ ‫•‬
‫مثل سالسل األحرف متغرية الطول واملتجهات وما إلى ذلك‪.‬‬ ‫•‬

‫يغطي هذا الفصل األنواع املدمجة ‪ built-in‬وهو بداية تغطيتنا لكيفية دعم يس‪ ++‬ألنواع أكرث تعقي ًدا‪.‬‬

‫تعرف األنواع معىن البيانات والعمليات في برامجنا‪ .‬فمعىن جملة بسيطة مثل‬

‫;‪i = i + j‬‬
‫تعتمد على نوعي ‪ i‬و ‪.j‬‬
‫إذا كانت ‪ i‬و ‪ j‬أعدا ًدا صحيحة ‪ ، integers‬فإن هذه الجملة لها معىن حسابي عادي وهو الجمع‪.‬‬ ‫•‬
‫أما إذا كانت ‪ i‬و ‪ j‬عبارة عن كائنات عنرص_مبيعات ‪ ،‬فإن هذه الجملة تجمع مكونات هذين العنرصين‪.‬‬ ‫•‬
‫‪ . 2٫1‬اﻷنــــــــــواع الـمدمجــــــــــة اﻷوليــــــــــة‬

‫‪2.1. Primitive Built-in Types‬‬

‫خاصا يسمى فراغ ‪.void‬‬


‫ً‬ ‫ونوعا‬
‫ً‬ ‫تعرف لغة يس‪ ++‬مجموعة من األنواع البدائية اليت تتضمن األنواع الحسابية‬
‫تمثل األنواع الحسابية األحرف ‪ characters‬واألعداد الصحيحة ‪، integers‬‬ ‫•‬
‫والقيم املنطقية ‪ boolean values‬وأرقام النقطة العائمة العرشية ‪. floating-point numbers‬‬ ‫•‬
‫ال يحتوي النوع فراغ ‪ void‬على قيم مقرتنة به وﻻ يمكن استخدامه إﻻ في حاالت قليلة فقط ‪،‬‬ ‫•‬
‫شيوعا عندما يستخدم كنوع إعادة لدوال ال تعيد قيمة‪.‬‬
‫ً‬ ‫وأكرث حاﻻت استخدامه‬ ‫•‬

‫‪ 2٫1٫1‬اﻷنواع الحسابية‬
‫‪2.1.1. Arithmetic Types‬‬

‫تنقسم األنواع الحسابية إلى صنفني‪:‬‬


‫األنواع الصحيحة ‪( integral types‬شاملة الحرف ‪ character‬واملنطقي ‪) boolean‬‬ ‫•‬
‫واألنواع ذات النقطة العائمة ‪.floating-point‬‬ ‫•‬

‫يختلف حجم األنواع الحسابية ‪ -‬وهو عدد وحدات البت ‪ -‬عرب األجهزة‪.‬‬
‫يضمن املعيار الحد األدنى لألحجام كما هو موضح في الجدول التالي ‪ .2.1‬ومع ذلك ‪،‬‬ ‫•‬
‫يُسمح للمرتجمني باستخدام أحجام أكرب لهذه األنواع‪.‬‬ ‫•‬
‫أيضا‪.‬‬
‫ونظرًا الختالف عدد وحدات البت ‪ ،‬فإن أكرب (أو أصغر) قيمة يمكن أن يمثلها النوع قد تختلف ً‬ ‫•‬

‫الجدول ‪ .2.1‬يس‪ :++‬أنواع حسابية‬

‫النوع‬ ‫معناه‬ ‫الحجم اﻷدنى‬

‫‪bool‬‬ ‫منطقي‬ ‫ﻻ يوجد‬


‫‪char‬‬ ‫حرف‬ ‫‪8 bit‬‬
‫‪wchar_t‬‬ ‫حرف موسع ‪wide character‬‬ ‫‪16 bit‬‬
‫‪char16_t‬‬ ‫حرف ترمزي موحد ‪Unicode character‬‬ ‫‪16 bit‬‬
‫‪char32_t‬‬ ‫حرف ترمزي موحد ‪Unicode character‬‬ ‫‪32 bit‬‬
‫‪short‬‬ ‫عدد صحيح قصري‬ ‫‪16 bit‬‬
‫‪int‬‬ ‫عدد صحيح عادي‬ ‫‪16 bit‬‬
‫‪long‬‬ ‫عدد صحيح طويل‬ ‫‪32 bit‬‬
‫‪long long‬‬ ‫عدد صحيح طويل الطويل‬ ‫‪64 bit‬‬
‫‪float‬‬ ‫عائمة عرشية أحادية الدقة‬ ‫‪ 6‬خانات رقمية‬
‫‪double‬‬ ‫عرشية مزدوجة الدقة‬ ‫‪ 10‬خانات رقمية‬
‫‪long double‬‬ ‫عرشية طويلة مزدوجة الدقة‬ ‫‪ 10‬خانات رقمية‬

‫يمثل النوع املنطقي قيم الحقيقة وهي الصواب ‪ true‬والخطأ ‪.false‬‬

‫هناك العديد من أنواع األحرف ‪ ،‬معظمها موجود لدعم التدويل‪.‬‬


‫نوع الحرف األسايس هو ‪ .char‬تم ضمان حجم الحرف أن يكون كبريًا بما يكفي‬ ‫•‬
‫ليستوعب القيم الرقمية املقابلة لألحرف املوجودة في مجموعة األحرف األساسية للجهاز‪.‬‬ ‫•‬
‫وهذا يعين أن حجم الحرف هو نفس حجم البايت الواحد‪.‬‬ ‫•‬

‫تستخدم أنواع األحرف املتبقية – ‪ wchar_t‬و ‪ char16_t‬و ‪ – char32_t‬ملجموعات األحرف املوسعة‪.‬‬


‫تضمن اللغة أن حجم ‪ wchar_t‬كبري بحيث يستوعب أي حرف في أكرب مجموعة أحرف موسعة بالجهاز‪.‬‬ ‫•‬
‫تم تخصيص النوعني ‪ char16_t‬و ‪ char32_t‬ألحرف الرتمزي املوحد ‪.Unicode‬‬ ‫•‬
‫‪ Unicode‬عبارة عن معيار لتمثيل األحرف املستخدمة في أي لغة طبيعية بشكل أسايس‪.‬‬ ‫•‬

‫قيما صحيحة ألحجام مختلفة (محتملة)‪.‬‬


‫تمثل األنواع الصحيحة املتبقية ً‬
‫تضمن اللغة أن يكون حجم العدد الصحيح العادي على األقل كبرياً بحجم القصري ‪، short‬‬ ‫•‬
‫وأن يكون حجم الصحيح ‪ long‬الطويل كبريا على األقل بحجم الصحيح العادي‪،‬‬ ‫•‬
‫و أن يكون حجم ‪ long long‬كبريا على األقل بمقدار طول ‪.long‬‬ ‫•‬
‫تم تقديم النوع ‪ long long‬في املعيار الجديد‪.‬‬ ‫•‬

‫تمثل أنواع العائمة العرشية قيم الدقة املفردة واملزدوجة واملمتدة‪.‬‬


‫يعرف املعيار الحد األدنى لعدد الخانة الرقمية‪.‬‬ ‫•‬
‫معظم املرتجمات توفر دقة أكرث من الحد األدنى املعرف‪.‬‬ ‫•‬
‫وعاد ًة ما يتم تمثيل العائمات ‪ floats‬في كلمة واحدة ‪ 32‬بت ‪ ،‬واملزدوجة ‪ double‬في كلمتني ‪ 64‬بت ‪،‬‬ ‫•‬
‫واملزدوجة الطويلة ‪ long double‬في ثالث أو أربع كلمات (‪ 96‬أو ‪ 128‬بت)‪.‬‬ ‫•‬
‫رقما عرشيا ‪ ،‬على التوالي‪.‬‬
‫وعاد ًة ما ينتج النوعان العائم واملزدوج حوالي ‪ 7‬و ‪ً 16‬‬ ‫•‬
‫وغالبا يستخدم النوع ‪ long double‬كطريقة الستيعاب أجهزة النقاط العائمة ذات األغراض الخاصة ؛‬ ‫ً‬ ‫•‬
‫واليت يرجح أن تختلف دقتها من تطبيق إلى آخر‪.‬‬ ‫•‬

‫التمثيل على مستوى اآللة لألنواع املدمجة‬

‫‪Machine-Level Representation of the Built-in Types‬‬

‫تخزن أجهزة الكمبيوتر البيانات كسلسلة من البتات ‪، bits‬‬ ‫•‬


‫كل منها يحتوي على إحدى القيمتني صفر ‪ 0‬أو واحد ‪ ، 1‬مثل‬ ‫•‬

‫‪00011011011100010110010000111011 ...‬‬
‫تتعامل معظم أجهزة الكمبيوتر مع الذاكرة على أنها أجزاء من وحدات بت ذات قوة تبلغ ‪.2‬‬ ‫•‬
‫يشار إلى أصغر جزء من الذاكرة القابلة للعنونة باسم "بايت ‪."byte‬‬ ‫•‬
‫يُشار إلى وحدة التخزين األساسية ‪ ،‬اليت تتكون عاد ًة من عدد صغري من البايتات ‪ ،‬باسم "كلمة ‪."word‬‬ ‫•‬
‫في لغة يس‪ ، ++‬يحتوي البايت على ما ال يقل عن عدد البتات املطلوبة‬ ‫•‬
‫ﻻستيعاب حرف في مجموعة األحرف األساسية للجهاز‪.‬‬ ‫•‬
‫في معظم األجهزة ‪ ،‬يحتوي البايت على ‪ 8‬بتات وتحتوي الكلمة إما على ‪ 32‬أو ‪ 64‬بت ‪ ،‬أي ‪ 4‬أو ‪ 8‬بايت‪.‬‬ ‫•‬

‫رقما (يسمى "عنوان ‪ )"address‬بكل بايت في الذاكرة‪.‬‬


‫تربط معظم أجهزة الكمبيوتر ً‬ ‫•‬
‫فعلى جهاز به ‪ 8‬بايتات وكلمات ‪ 32‬بت ‪ ،‬قد نعرض كلمة من الذاكرة على النحو التالي‬ ‫•‬

‫‪736424‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬


‫‪736425‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬
‫‪736426‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬
‫‪736427‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬

‫هنا ‪ ،‬يكون عنوان البايت على اليسار ‪ ،‬مع ‪ 8‬بتات من البايت تتبع العنوان‪.‬‬ ‫•‬

‫يمكن استخدام عنوان ما ليشري إلى أي من مجموعات وحدات بت عديدة مختلفة األحجام تبدأ من العنوان‪.‬‬ ‫•‬
‫من املمكن قول أن الكلمة على العنوان ‪ 736424‬أو نقول البايت على العنوان ‪.736427‬‬ ‫•‬
‫إلعطاء معىن للذاكرة في عنوان معني ‪ ،‬يجب أن نعرف نوع القيمة املخزنة هناك‪.‬‬ ‫•‬
‫يعرف النوع عدد البتات املستخدمة وكيفية تفسري تلك البتات‪.‬‬ ‫•‬

‫إذا كان الكائن في املوقع ‪ 736424‬يحتوي على عائمة عرشية ‪، float‬‬ ‫•‬
‫وتم تخزين العائمات العرشية ‪ floats‬على هذا الجهاز في ‪ 32‬بت ‪،‬‬ ‫•‬
‫فإننا نعلم أن الكائن في هذا العنوان يمتد إلى كلمة بأكملها‪.‬‬ ‫•‬
‫تعتمد قيمة هذا العائم العرشي ‪ float‬على تفاصيل كيفية تخزين اآللة ألرقام العائمة العرشية‪.‬‬ ‫•‬
‫بدال ً من ذلك ‪ ،‬إذا كان الكائن في املوقع ‪ 736424‬عبارة عن حرف بال_إشارة ‪،‬‬ ‫•‬
‫وذلك على جهاز باستخدام مجموعة أحرف ‪، ISO-Latin-1‬‬ ‫•‬
‫فإن البايت املوجود في هذا العنوان تمثل فاصلة عرشية‪.‬‬ ‫•‬

‫اﻷنواع ذات اﻹشارة واﻷنواع بال_إشارة‬


‫‪Signed and Unsigned Types‬‬

‫باستثناء األنواع املنطقية وأنواع األحرف املوسعة ‪ ،‬قد تكون األنواع الصحيحة بإشارة أو بال_إشارة ‪:‬‬
‫فالنوع ذو اﻹشارة ‪ signed‬يحتوي األرقام السالبة أو املوجبة (بما في ذلك الصفر) ؛‬ ‫•‬
‫بينما يمثل النوع بال_إشارة ‪ unsigned‬فقط قيماً موجب ًة أكرب من أو تساوي الصفر‪.‬‬ ‫•‬
‫األنواع ‪ ، int‬و ‪ ، short‬و ‪ ، long‬و ‪ long long‬كلها ذات إشارة ‪.signed‬‬ ‫•‬
‫نحصل على النوع املقابل بال_إشارة عن طريق إضافة كلمة ال_إشارة إلى النوع ‪ ،‬مثل ‪unsigned long‬‬ ‫•‬
‫قد يتم اختصار نوع ‪ int‬بال_إشارة ‪ unsigned int‬إلى ‪ unsigned‬فقط‪.‬‬ ‫•‬

‫على عكس أنواع األعداد الصحيحة األخرى ‪ ،‬هناك ثالثة أنواع أساسية ممزية من األحرف‪:‬‬
‫‪ ، char‬و ‪ char‬بإشارة ‪ ،‬و ‪ char‬بال_إشارة‪.‬‬ ‫•‬
‫على وجه الخصوص ‪ ،‬النوع ‪ char‬ال يعترب نفس نوع ‪.signed char‬‬ ‫•‬
‫وعلى الرغم من وجود ثالثة أنواع من األحرف ‪ ،‬إال أنه ال يوجد سوى تمثيلني‪ :‬بإشارة وبال_إشارة‪.‬‬ ‫•‬
‫يستخدم نوع الحرف (العادي) أحد هذين التمثيلني‪.‬‬ ‫•‬
‫أي من التمثيالت األخرى ذات األحرف املكافئة لـ ‪ char‬تعتمد على املرتجم‪.‬‬ ‫•‬

‫في النوع بال_إشارة ‪ ،‬تمثل جميع البتات قيمة‪.‬‬


‫على سبيل املثال ‪ ،‬يمكن أن تحتوي األحرف غري املؤرشة ذات ‪-8‬بت على القيم من ‪ 0‬إلى ‪ 255‬ضمناً‪.‬‬ ‫•‬

‫ال يحدد املعيار كيفية تمثيل األنواع ذات اﻹشارة ‪،‬‬


‫ولكنه يحدد أنه يجب تقسيم النطاق بالتساوي بني القيم املوجبة والسالبة‪ .‬ومن ثم ‪،‬‬ ‫•‬
‫قادرا على االحتفاظ بقيم من سالب ‪ 127‬حىت موجب ‪ 127‬؛‬
‫ً‬ ‫فإن حرف ‪-8‬بت بإشارة تضمن اللغة أن يكون‬ ‫•‬
‫بينما تستخدم معظم اآلالت الحديثة تمثيالت تسمح بقيم من سالب ‪ 128‬إلى املوجب ‪.127‬‬ ‫•‬

‫قسم التمارين ‪2.1.1‬‬

‫تمرين ‪:2.1‬‬
‫‪ -‬ما هي االختالفات بني ‪int ، long ، long long ، short‬؟‬
‫‪ -‬وبني ‪ unsigned type‬و‪signed‬؟‬
‫‪ -‬وبني ‪ float‬و ‪ double‬؟‬

‫تمرين ‪:2.2‬‬
‫‪ -‬لحساب دفعة الرهن العقاري ‪ ،‬ما هي األنواع اليت ستستخدمها في املعدل ‪ ،‬واملبلغ األسايس ‪ ،‬واملدفوعات؟‬
‫‪ -‬ارشح سبب اختيار كل نوع‪.‬‬

‫نصيحة ‪ :‬حدد النوع املطلوب استخدامه‬

‫‪Deciding which Type to Use‬‬

‫تم تصميم يس‪ ، ++‬بشكل مشابه للغة يس ‪ ،‬حيث تسمح للربامج باالقرتاب من األجهزة عند الرضورة‪.‬‬ ‫•‬
‫ويتم تعريف األنواع الحسابية لتلبية الخصائص املمزية ألنواع مختلفة من األجهزة‪.‬‬ ‫•‬

‫وف ًقا لذلك ‪ ،‬يمكن أن يكون عدد األنواع الحسابية في يس‪ ++‬محريًا‪.‬‬ ‫•‬
‫يمكن (وينبغي) ملعظم املربمجني تجاهل هذه التعقيدات من خالل تقييد األنواع اليت يستخدمونها‪.‬‬ ‫•‬
‫يمكن أن تكون بعض القواعد األساسية مفيدة في تحديد النوع الذي يجب استخدامه كالتالي ‪:‬‬
‫استخدم النوع بال_إشارة ‪ unsigned‬عندما تعلم أن القيم ال يمكن أن تكون سالبة‪.‬‬ ‫•‬
‫استخدام عدد صحيح ‪ int‬للعمليات الحسابية‪.‬‬ ‫•‬
‫غالبا ما يكون للطويل نفس حجم ‪ int‬العادي‪.‬‬
‫ً‬ ‫قد يكون القصري ‪ short‬عادة صغريًا ج ًدا ‪ ،‬وعملياً ‪،‬‬ ‫•‬
‫إذا كانت قيم بياناتك أكرب من الحد األدنى للحجم املضمون لـ ‪ ، int‬فاستخدم ‪.long long‬‬ ‫•‬
‫منطقيا ‪ bool‬في التعبريات الحسابية‪.‬‬
‫ً‬ ‫عاديا ‪ char‬أو‬
‫ً‬ ‫ال تستخدم حر ًفا‬ ‫•‬
‫استخدمهما فقط لالحتفاظ باألحرف أو قيم منطقية‪.‬‬ ‫•‬
‫تعد العمليات الحسابية باستخدام ‪ char‬مشكلة بشكل خاص‬ ‫•‬
‫وذلك ألن الحرف ‪ char‬يكون بإشارة على بعض األجهزة وبال_إشارة على أجهزة أخرى‪.‬‬ ‫•‬
‫صحيحا صغريًا ‪ ،‬فحدد رصاح ًة أحر ًفا بإشارة أو أحر ًفا بال_إشارة‪.‬‬
‫ً‬ ‫إذا كنت تريد عد ًدا‬ ‫•‬
‫استخدم ‪ double‬للحساب العرشي‪ .‬العائم الفردي ‪ float‬عادة ال يحتوي على دقة كافية ‪،‬‬ ‫•‬
‫وتكلفة العمليات الحسابية ذات الدقة املزدوجة مقابل الدقة املفردة ال تكاد تذكر‪.‬‬ ‫•‬
‫في الواقع ‪ ،‬في بعض األجهزة ‪ ،‬تكون العمليات ذات الدقة املزدوجة أرسع من عمليات الدقة الفردية‪.‬‬ ‫•‬
‫وعاد ًة ما تكون الدقة اليت يوفرها املزدوج الطويل ‪ long double‬غري رضورية ‪،‬‬ ‫•‬
‫كذلك تستلزم غالبًا تكلفة وقت تشغيل كبرية‪.‬‬ ‫•‬

‫‪ 2٫1٫2‬تحويالت النوع‬
‫‪2.1.2. Type Conversions‬‬

‫يعر ف نوع الكائن البيانات اليت قد يحتويها الكائن والعمليات اليت يمكن أن يؤديها‪.‬‬
‫ّ‬
‫ومن بني عمليات تدعمها عدة أنواع القدرة على تحويل كائنات نوع محدد إلى أنواع أخرى ذات صلة‪.‬‬ ‫•‬

‫تلقائيا عندما نستخدم كائنًا من أحد اﻷنواع حيث يتوقع كائن من نوع مختلف‪.‬‬
‫ً‬ ‫تحدث تحويالت نوع الكائن‬
‫سيكون لدينا املزيد لنقوله عن التحويالت الح ًقا ‪،‬‬ ‫•‬
‫ولكن في الوقت الحالي من املفيد فهم ما يحدث عندما نخصص قيمة من نوع ما إلى كائن من نوع آخر‪.‬‬ ‫•‬

‫حسابيا إلى نوع آخر‪:‬‬


‫ً‬ ‫نوعا‬
‫عندما نخصص ً‬

‫;‪bool b = 42‬‬ ‫‪// b is true‬‬


‫‪int i‬‬ ‫;‪= b‬‬ ‫‪// i has value 1‬‬
‫;‪I = 3.14‬‬ ‫‪// i has value 3‬‬
‫‪double pi = i; // pi has value 3.0‬‬
‫‪unsigned char c = -1; // assuming 8-bit chars, c has value 255‬‬
‫‪signed char c2 = 256; // assuming 8-bit chars, value of c2 is undefined‬‬

‫يعتمد ما يحدث على نطاق القيم اليت تسمح بها األنواع‪:‬‬


‫عندما نقوم بتعيني أحد األنواع الحسابية غري املنطقية إلى كائن منطقي ‪،‬‬ ‫•‬
‫فستكون النتيجة خاطئة ‪ false‬إذا كانت القيمة صفر ‪ 0‬وستكون ‪ true‬بخالف ذلك‪.‬‬ ‫•‬
‫عندما نقوم بتعيني منطقي إلى أحد األنواع الحسابية األخرى ‪،‬‬ ‫•‬
‫صحيحا ‪ true‬و ‪ 0‬إذا كان املنطقي خطأ ‪.false‬‬
‫ً‬ ‫تكون القيمة الناتجة ‪ 1‬إذا كان املنطقي‬ ‫•‬
‫عندما نقوم بتعيني قيمة عرشية عائمة‪/‬مزدوجة ‪ float/double‬على كائن نوع صحيح ‪،‬‬ ‫•‬
‫فسوف يتم اقتطاع القيمة العرشية‪.‬‬ ‫•‬
‫القيمة اليت ستخزن هي العدد الصحيح الذي يسبق العالمة العرشية‪.‬‬ ‫•‬
‫عندما نخصص قيمة صحيحة ‪ integral‬لكائن نوع عرشي عائم‪/‬مزدوج ‪ ،‬يكون الجزء الكرسي صفرًا‪.‬‬ ‫•‬
‫قد تُفقد الدقة إذا كان العدد الصحيح يحتوي على بتات أكرث مما يمكن أن يستوعبه الكائن العرشي‪.‬‬ ‫•‬
‫إذا قمنا بتعيني قيمة خارج نطاق كائن من نوع بال_إشارة ‪، unsigned‬‬ ‫•‬
‫فإن النتيجة هي باقي وحدة القيمة اليت يمكن أن يحتفظ بها نوع الهدف‪.‬‬ ‫•‬
‫على سبيل املثال ‪ ،‬يمكن أن تحتوي األحرف بال_إشارة ‪ unsigned character‬ذات ‪ 8‬بت ‪،‬‬ ‫•‬
‫على القيم من ‪ 0‬إلى ‪ ، 255‬ضمناً‪.‬‬ ‫•‬
‫إذا قمنا بتعيني قيمة خارج ذلك النطاق ‪ ،‬يقوم املرتجم بتعيني باقي قسمة تلك القيمة على ‪.256‬‬ ‫•‬
‫لذلك ‪ ،‬فإن تعيني –‪ 1‬على حرف من ‪-8‬بت بال إشارة يعطي هذا الكائن قيمة ‪.255‬‬ ‫•‬
‫إذا قمنا بتعيني قيمة خارج النطاق لكائن من نوع ذو إشارة ‪ ،‬فإن النتيجة تكون غري معرفة‪.‬‬ ‫•‬
‫قد يظهر أن الربنامج يعمل ‪ ،‬أو قد يتعطل ‪ ،‬أو قد ينتج مخلفات قيم سابقة ‪.garbage values‬‬ ‫•‬

‫يطبق املرتجم هذه التحويالت من النوع نفسه عندما نستخدم قيمة من نوع حسابي ‪،‬‬
‫حيث يتوقع وجود قيمة نوع حسابي مختلف‪.‬‬ ‫•‬

‫على سبيل املثال ‪ ،‬عندما نستخدم قيمة غري منطقية كرشط ‪،‬‬
‫يتم تحويل القيمة الحسابية إلى قيمة منطقية بنفس الطريقة اليت سيتم بها تحويلها ‪،‬‬ ‫•‬
‫إذا قمنا بتعيني هذه القيمة الحسابية كمتغري منطقي‪:‬‬ ‫•‬

‫;‪int i = 42‬‬
‫‪if (i) // condition will evaluate as true‬‬
‫;‪i = 0‬‬

‫فإن كانت القيمة ‪ ، 0‬فالرشط خطأ ‪ false‬؛ جميع القيم األخرى (عدا الصفر) تعطي القيمة صحيح ‪.true‬‬ ‫•‬
‫دائما إلى ‪ 0‬أو ‪.1‬‬
‫ً‬ ‫منطقيا في تعبري حسابي ‪ ،‬تتحول قيمته‬
‫ً‬ ‫وعلى نفس املنوال ‪ ،‬عندما نستخدم نوعا‬ ‫•‬
‫نتيجة لذلك ‪ ،‬فإن استخدام نوع منطقي في تعبري حسابي يكاد يكون غري سليم‪.‬‬ ‫•‬

‫املعرف وسلوك التعريف بالتنفيذ‬


‫ّ‬ ‫نصيحة ‪ :‬تجنب السلوك غري‬

‫‪Avoid Undefined and Implementation-Defined Behavior‬‬

‫قادرا على) اكتشافها‪.‬‬


‫ً‬ ‫ينتج السلوك غري املعرف أخطاء ال يتطلب من املرتجم (وأحيا ًنا ال يكون‬ ‫•‬
‫حىت إن تمت ترجمة اﻷكواد برمجياً ‪ ،‬فإن برنامجا ينفذ تعبريًا غري معرف يكون خطأ‪.‬‬ ‫•‬

‫لسوء الحظ ‪ ،‬يمكن أن تبدو أن الربامج اليت تحتوي على سلوك غري معرف ‪،‬‬ ‫•‬
‫كأنها تتنفذ بشكل صحيح في بعض الظروف و ‪ /‬أو مع بعض املرتجمات‪.‬‬ ‫•‬
‫لكن ليس هناك ما يضمن أن برنامجا ‪ ،‬تمت ترجمته تحت مرتجم مختلف ‪،‬‬ ‫•‬
‫أو حىت إصدار الحق من نفس املرتجم ‪ ،‬سيستمر في العمل بشكل صحيح‪.‬‬ ‫•‬
‫وال يوجد أي ضمان على أن ما يعمل مع مجموعة من املدخالت سيعمل مع مجموعة أخرى‪.‬‬ ‫•‬

‫وباملثل ‪ ،‬يفرتض أن تتجنب الربامج عاد ًة طرق التعريف بالتنفيذ ‪،‬‬ ‫•‬
‫مثل افرتاض أن حجم ‪ int‬هو قيمة ثابتة ومعروفة‪.‬‬ ‫•‬
‫يقال أن مثل هذه الربامج غري قابلة للنقل‪.‬‬ ‫•‬
‫فعندما يتم نقل الربنامج إلى جهاز آخر ‪ ،‬قد تفشل األكواد اليت تعتمد على طرق التعريف بالتنفيذ‪.‬‬ ‫•‬

‫إن تعقب هذه األنواع من املشاكل في الربامج اليت كانت تعمل ساب ًقا هو ‪ ،‬باعتدال أمر غري سار‪.‬‬

‫تعبريات تتضمن أنواعاً بال_إشارة‬


‫‪Expressions Involving Unsigned Types‬‬

‫على الرغم من أنه من غري املحتمل أن نعنّي عن قصد قيمة سالبة لكائن نوع بال_إشارة ‪،‬‬
‫ضمنيا‪.‬‬
‫ً‬ ‫يمكننا (بكل سهولة) كتابة كود يفعل ذلك‬ ‫•‬
‫على سبيل املثال ‪ ،‬إذا استخدمنا قيماً بال_إشارة ‪ 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‬‬

‫في أول تعبري ‪،‬‬


‫نجمع قيميت ‪( int‬سلبيتني) ونحصل على النتيجة املتوقعة‪.‬‬ ‫•‬
‫أما في التعبري الثاني ‪ ،‬يتم تحويل القيمة ‪ 42-‬إلى بال_إشارة قبل إتمام الجمع‪.‬‬ ‫•‬
‫يترصف تحويل رقم سالب إلى رقم بال_إشارة (موجب) ‪،‬‬ ‫•‬
‫تماما كما لو كنا قد حاولنا تعيني تلك القيمة السالبة إلى كائن بال_إشارة‪.‬‬
‫ً‬ ‫•‬
‫تدور النتيجة حول القيمة كما هو موضح أعاله‪.‬‬ ‫•‬
‫وبغض النظر عما إذا كان أحد املعاملني أو كالهما بال_إشارة ‪،‬‬ ‫•‬
‫إذا طرحنا قيمة ما من عدد بال_إشارة ‪ ،‬يجب أن نتأكد من أن النتيجة ال يمكن أن تكون سالبة‪:‬‬ ‫•‬

‫;‪unsigned u1 = 42, u2 = 10‬‬


‫‪std::cout << u1 - u2 << std::endl; // ok: result is 32‬‬
‫‪std::cout << u2 - u1 << std::endl; // ok: but result will wrap around‬‬

‫أيضا على كيفية كتابة الحلقات ‪.loops‬‬


‫حقيقة أن املتغري بال_إشارة ال يمكن أن يكون أقل من الصفر تؤثر ً‬
‫على سبيل املثال ‪ ،‬في التدريبات على الفقرة ‪،1٫4٫1‬‬ ‫•‬
‫كان عليك كتابة حلقة تستخدم عامل التناقص لطباعة األرقام من ‪ 10‬إلى الصفر‪.‬‬ ‫•‬
‫ربما ظهرت الحلقة اليت كتبتها شيًئ ا مثل‬ ‫•‬

‫)‪for (int i = 10; i >= 0; --i‬‬


‫;‪std::cout << i << std::endl‬‬

‫قد نعتقد أنه يمكننا إعادة كتابة هذه الحلقة باستخدام متغري بدون إشارة‪.‬‬
‫بعد كل يشء ‪ ،‬نحن ال نخطط لطباعة أرقام سالبة‪ .‬ومع ذلك ‪،‬‬ ‫•‬
‫فإن هذا التغيري البسيط في النوع يعين أن حلقتنا لن تنتهي أب ًدا ‪:‬‬ ‫•‬

‫‪// WRONG: u can never be less than 0; condition will always succeed‬‬
‫)‪for (unsigned u = 10; u >= 0; --u‬‬
‫;‪std::cout << u << std::endl‬‬

‫فكر فيما يحدث عندما تساوي ‪ u‬صفر‪.‬‬


‫في هذا التكرار ‪ ،‬نطبع ‪ 0‬ثم ننفذ بيان الحلقة ‪.for‬‬ ‫•‬
‫سيطرح التعبري ‪ --u‬واحداً من ‪ .u‬هذه النتيجة ‪ ، 1- ،‬لن تتناسب مع قيمة الال_إشارة‪.‬‬ ‫•‬
‫كما هو حال أي قيمة أخرى خارج النطاق ‪ ،‬سيتم تحويل ‪ 1-‬إلى قيمة بال_إشارة‪.‬‬ ‫•‬
‫على افرتاض ‪ 32‬بت ‪ ، ints‬نتيجة التناقص عندما ‪ ، u=0‬هو ‪.4294967295‬‬ ‫•‬

‫هناك طريقة واحدة لكتابة تلك الحلقة هي استخدام ‪ while‬بدال ً من ‪.for‬‬


‫• حيث تتيح لنا ‪ while‬استخدام تناقص القيمة قبل طباعة القيمة وليس بعدها ‪:‬‬

‫‪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‬‬
‫}‬

‫تبدأ هذه الحلقة بإنقاص قيمة متغري التحكم في الحلقة‪.‬‬ ‫•‬


‫في التكرار األخري ‪ ،‬ستكون ‪ u=1‬عند الدخول إلى الحلقة‪.‬‬ ‫•‬
‫سننقص هذه القيمة ‪ ،‬مما يعين أننا سنطبع ‪ 0‬في هذا التكرار‪.‬‬ ‫•‬
‫عندما نخترب ‪ u‬في املرة التالية ‪ ،‬ستكون قيمتها ‪ 0‬وستخرج الحلقة‪.‬‬ ‫•‬
‫وألننا نبدأ بإنقاص ‪ ، u‬علينا أن نهئي ‪ u‬إلى قيمة أكرب من القيمة األولى اليت نريد طباعتها‪.‬‬ ‫•‬
‫ومن ثم ‪ ،‬نقوم بتهيئة ‪ u‬على ‪ ، 11‬بحيث تكون القيمة األولى املطبوعة هي ‪.10‬‬ ‫•‬

‫احذر ‪ :‬ال تخلط بني األنواع املؤرشة وغري املؤرشة‬

‫يمكن أن تؤدي التعبريات اليت تجمع بني القيم ذات اﻹشارة والال_إشارة إلى نتائج مفاجئة ‪،‬‬ ‫•‬
‫عندما تكون القيمة ذات اﻹشارة سالبة‪.‬‬ ‫•‬
‫تلقائيا إلى قيم بال_إشارة‪.‬‬
‫ً‬ ‫من الرضوري أن تتذكر أنه يتم تحويل القيم ذات اﻹشارة‬ ‫•‬
‫على سبيل املثال ‪ ،‬في تعبري مثل ‪ ، a * b‬إذا كانت ‪ a‬تساوي ‪ 1-‬و ‪ b‬تساوي ‪، 1‬‬ ‫•‬
‫ٍ‬
‫فعندئذ إذا كان كل من ‪ a‬و ‪ b‬عبارة عن ‪ ، ints‬تكون القيمة كما هو متوقع ‪.1-‬‬ ‫•‬
‫لكن إذا كانت ‪ a int‬و ‪ b‬بال_إشارة ‪،‬‬ ‫•‬
‫فإن قيمة هذا التعبري تعتمد على عدد بتات ‪ int‬على الجهاز املعني‪.‬‬ ‫•‬
‫ينتج عن هذا التعبري على أجهزتنا ‪.4294967295‬‬ ‫•‬

‫قسم التمارين ‪2.1.2‬‬

‫تمرين ‪:2.3‬‬
‫ما هي املخرجات الذي سينتجه الكود التالي؟‬
‫;‪unsigned u = 10, u2 = 42‬‬
‫‪std::cout << u2 - u‬‬ ‫;‪<< std::endl‬‬
‫‪std::cout << u‬‬ ‫;‪- u2 << std::endl‬‬

‫‪int i = 10, i2‬‬ ‫;‪= 42‬‬


‫‪std::cout << i2 - i‬‬ ‫;‪<< std::endl‬‬
‫‪std::cout << i‬‬ ‫;‪- i2 << std::endl‬‬

‫;‪std::cout << i - u << std::endl‬‬


‫;‪std::cout << u - i << std::endl‬‬

‫تمرين ‪:2.4‬‬
‫برنامجا للتحقق مما إذا كانت توقعاتك صحيحة‪.‬‬
‫ً‬ ‫‪ -‬اكتب‬
‫‪ -‬إذا لم يكن األمر كذلك ‪ ،‬فقم بدراسة هذا القسم حىت تفهم ماهية املشكلة‪.‬‬

‫‪ 2٫1٫3‬الحرفيات‬
‫‪2.1.3. Literals‬‬
‫تُعرف قيمة ‪ ،‬مثل ‪ ، 42‬بالحرفية ‪ Literal‬ألن قيمتها بديهية‪ .‬فلكل حرفية نوع‪.‬‬
‫صياغة وقيمة الحرفية يحدد نوعها‪.‬‬ ‫•‬

‫حرفيات النقطة العائمة والعدد الصحيح‬


‫‪Integer and Floating-Point Literals‬‬

‫يمكننا كتابة عدد صحيح باستخدام‬


‫التدوين العرشي ‪ decimal: 0–9‬أو الثماني ‪ Octal: 0–7‬أو السدايس‪-‬عرشي ‪.Hexadecimal‬‬ ‫•‬
‫يتم تفسري الحرفية اليت تبدأ بـ ‪( 0‬صفر) على أنها رقم ثماني (أوكتال)‪.‬‬ ‫•‬
‫وتلك اليت تبدأ إما ‪ 0x‬أو ‪ 0X‬على أنها هيكساديسيمال ‪ /‬سدايس عرشي‪.‬‬ ‫•‬

‫على سبيل املثال ‪ ،‬يمكننا كتابة القيمة ‪ 20‬بأي من الطرق الثالث التالية‪:‬‬

‫* هيكساديسيمال سدايس عرشي * ‪/‬‬ ‫‪0x14‬‬ ‫* أوكتال ثماني *‬ ‫‪024‬‬ ‫* ديسيمال عرشي *‬ ‫‪20‬‬

‫يعتمد نوع حرفية عدد صحيح على قيمته وتدوينه‪.‬‬


‫افرتاضيا ‪ ،‬الحرفيات العرشية تكون ذات إشارة ؛‬ ‫•‬
‫بينما يمكن أن تكون حرفيات الثماني والسدايس‪-‬عرشي ذات إشارة أو بال_إشارة‪.‬‬ ‫•‬
‫تحتوي حرفية عرشية على أصغر نوع من ‪ ، int‬أو ‪ ، long‬أو ‪، long long‬‬ ‫•‬
‫(أي أول نوع في هذه القائمة) حيث تناسب قيمتها الحرفية‪.‬‬ ‫•‬
‫تحتوي الحرفية الثمانية والسدايس‪-‬عرشية على أصغر نوع من ‪، int‬‬ ‫•‬
‫أو ‪ int‬بال_إشارة ‪ ،‬أو ‪ ، long‬أو ‪ long‬بال_إشارة ‪ ،‬أو ‪، long long‬‬ ‫•‬
‫أو ‪ long long‬بال_إشارة حيث تناسب قيمتها الحرفية‪.‬‬ ‫•‬
‫من الخطأ استخدام حرفي كبري ج ًدا بحيث ال يتناسب مع نوع أكرب ذي صلة‪.‬‬ ‫•‬
‫فال توجد حرفية لنوع ‪.short‬‬ ‫•‬

‫سرنى في الجدول ‪ 2.2‬أنه يمكننا تجاوز هذه اإلعدادات االفرتاضية باستخدام الحقة‪.‬‬
‫الجدول ‪ .2.2‬تحديد نوع حرفي‬

‫حرفيات أعداد صحيحة‬ ‫حرفيات حرف وسالسل أحرف‬


‫‪Integer literals‬‬ ‫‪character and character string literals‬‬

‫رمز‬
‫أقل نوع‬ ‫رمز اإللحاق‬ ‫النوع‬ ‫املعىن‬
‫البداية‬
‫‪ 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‬‬

‫النوع‬ ‫رمز اإللحاق‬


‫‪ Float‬عدد فاصلة عرشية أحادي الدقة‬ ‫‪ f‬أو ‪F‬‬
‫‪ Long double‬عدد فاصلة عرشية طويل مزدوج‬ ‫‪ l‬أو ‪L‬‬

‫بالرغم من أنه يسمح بتخزين حرفيات األعداد الصحيحة في أنواع بإشارة ‪،‬‬
‫سالبا أب ًدا‪.‬‬
‫ً‬ ‫رقما‬
‫إﻻ أنه من الناحية الفنية ‪ ،‬ﻻ تعد الحرفية العرشية ً‬ ‫•‬
‫جزءا من الحرفية‪.‬‬
‫ً‬ ‫فإذا كتبنا ما يبدو أنه حرفية عرشية سالبة ‪ ،‬مثالً ‪ ، 42-‬فال تعد عالمة الطرح‬ ‫•‬
‫عالمة الطرح هي عامل ينفي حرفية معامله‪.‬‬ ‫•‬

‫أسا محد ًدا باستخدام التدوين العلمي‪.‬‬


‫تتضمن حرفيات النقطة‪-‬العائمة العرشية إما فاصلة عرشية أو ً‬
‫باستخدام التدوين العلمي ‪ ،‬تتم اإلشارة إلى األس بواسطة ‪ E‬أو ‪: e‬‬ ‫•‬

‫‪3.14159‬‬ ‫‪3.14159E0‬‬ ‫‪0.‬‬ ‫‪0e0‬‬ ‫‪.001‬‬

‫افرتاضياً ‪ ،‬تحتوي حرفية النقطة‪-‬العائمة العرشية على نوع مزدوج‪.‬‬


‫يمكننا تجاوز ذلك االفرتايض باستخدام الحقة من الجدول ‪ 2.2‬أعاله‪.‬‬ ‫•‬

‫حرفيات الحرف وسلسلة الحرف‬


‫‪Character and Character String Literals‬‬

‫الحرف املضمن داخل عالميت اقتباس مفردتني هو حرفية من نوع ‪.char‬‬


‫األحرف الصفرية أو األكرث املحاطة بعالمات اقتباس مزدوجة عبارة عن سلسلة أحرف ‪:‬‬ ‫•‬

‫'‪'a‬‬ ‫‪// character literal‬‬


‫"!‪"Hello World‬‬ ‫‪// string‬‬ ‫‪literal‬‬

‫نوع حرفية سلسلة عبارة عن مصفوفة من أحرف ثابتة ‪ ،‬وهو نوع سنناقشه في الفصل الثالث‪.‬‬
‫فارغا (’\‪ )’0‬بكل حرفية سلسلة‪.‬‬
‫ً‬ ‫يُلحق املرتجم حر ًفا‬ ‫•‬
‫وبالتالي ‪ ،‬فإن الحجم الفعلي لحرفية سلسلة تزيد بمقدار واحد عن حجمها الظاهري‪.‬‬ ‫•‬
‫فمثالً ‪ ،‬تمثل الحرفية ‘‪ ’A‬الحرف املفرد ‪، A‬‬ ‫•‬
‫بينما تمثل حرفية السلسلة "‪ "A‬مصفوفة من حرفني ‪ ،‬حرف ‪ A‬والحرف الفارغ‪.‬‬ ‫•‬

‫ﻻ يتم ربط حرفيتا سلسلة تبدو متجاورتني ومفصولة إﻻ بمسافات ‪،‬‬


‫أو حرف تاب (مسافة غري قابلة للطباعة) أو أسطر جديدة يتم ربطهما إلى حرفية سلسلة وحيدة‪.‬‬ ‫•‬
‫نستخدم هذا النموذج من الحرفية عندما نحتاج إلى كتابة حرفية ﻻ يمكن كتابتها بغري ذلك ‪،‬‬ ‫•‬
‫كونها أكرب من أن تتناسب بشكل مريح في سطر واحد ‪:‬‬ ‫•‬

‫‪// multi-line string literal‬‬


‫" ‪std::cout << "a really, really long string literal‬‬
‫;‪"that spans two lines" << std::endl‬‬

‫تسلسل الهروب‬
‫‪Escape Sequences‬‬

‫بعض اﻷحرف ليس لها صورة مرئية ‪-‬مثل املسافة لخلف أو أحرف تحكم‪.-‬‬
‫هذه األحرف غري قابلة للطباعة‪.‬‬ ‫•‬
‫األحرف األخرى لها معىن خاص في اللغة ‪،‬‬ ‫•‬
‫(كعالمات االقتباس املفردة واملزدوجة وعالمة االستفهام والرشطة املائلة للخلف)‪.‬‬ ‫•‬
‫ال يمكن لربامجنا استخدام أي من تلك األحرف مبارشة‪ .‬بدال ً من ذلك ‪،‬‬ ‫•‬
‫نستخدم تسلسل الهروب لتمثل تلك األحرف‪.‬‬ ‫•‬

‫يبدأ تسلسل الهروب برشطة مائلة للخلف‪ .‬تحدد اللغة عدة تسلسالت هروب ‪:‬‬

‫‪Newline‬‬ ‫‪horizontal tab‬‬ ‫)‪alert (bell‬‬


‫سطر جديد‬ ‫‪\n‬‬ ‫تاب أفقي‬ ‫‪\t‬‬ ‫جرس أو تنبيه‬ ‫‪\a‬‬

‫‪vertical tab‬‬ ‫‪Backspace‬‬ ‫‪double quote‬‬


‫تاب عمودي‬ ‫‪\v‬‬ ‫مسافة للخلف‬ ‫‪\b‬‬ ‫عالمة اقتباس مزدوج‬ ‫"\‬

‫‪Backslash‬‬ ‫‪question mark‬‬ ‫‪single quote‬‬


‫مائلة للخلف‬ ‫\\‬ ‫عالمة استفهام‬ ‫?\‬ ‫عالمة اقتباس مفردة‬ ‫'\‬

‫‪carriage return‬‬ ‫‪Form-feed‬‬


‫إعادة حرف‬ ‫‪\r‬‬ ‫تغذية نموذجية‬ ‫‪\f‬‬

‫نستخدم تسلسل الهروب كحرف واحد ‪:‬‬

‫;'‪std::cout << '\n‬‬ ‫‪// prints a newline‬‬


‫;"‪std::cout << "\tHi!\n‬‬ ‫‪// prints a tab followed by "Hi!" and a newline‬‬
‫أيضا تسلسل هروب عام ‪،‬‬
‫يمكننا أن نكتب ً‬
‫متبوعا بـ ‪ x‬ثم رقم سدايس عرشي واحد أو أكرث‬
‫ً‬ ‫تكون عبارة عن \‬ ‫•‬
‫متبوعا برقم ثماني واحد أو رقمني أو ثالثة‪.‬‬
‫ً‬ ‫أو \‬ ‫•‬
‫تمثل قيمة الرقم القيمة العددية املكافئة للحرف‪.‬‬ ‫•‬

‫وإليك بعض األمثلة (بافرتاض مجموعة األحرف الالتينية‪:)1-‬‬

‫)‪\7 (bell‬‬ ‫)‪\12 (newline‬‬ ‫)‪\40 (blank‬‬


‫)‪\0 (null‬‬ ‫)'‪\115 ('M‬‬ ‫)'‪\x4d ('M‬‬

‫كما هو الحال مع تسلسل الهروب الذي تعرفه اللغة ‪ ،‬نستخدم تسلسالت الهروب هذه كما نستخدم أي حرف آخر‪:‬‬

‫;"‪std::cout << "Hi \x4dO\115!\n‬‬ ‫‪// prints Hi MOM! followed by a newline‬‬


‫;'‪std::cout << '\115' << '\n‬‬ ‫‪// prints M followed by a newline‬‬

‫الحظ ‪،‬‬
‫متبوعا بأكرث من ثالثة أرقام ثمانية ‪ ،‬فسرتبط به الثالثة األولى فقط‪.‬‬
‫ً‬ ‫أنه إن كان الباك‪-‬فالش \‬ ‫•‬
‫على سبيل املثال ‪ ،‬يمثل "\ ‪ "1234‬حرفني‪ :‬الحرف الذي يتم تمثيله بالتمثيل الثماني ‪ 123‬والحرف ‪.4‬‬ ‫•‬
‫في املقابل ‪ ،‬يستخدم \ الباك‪-‬فالش املتبوع بـ ‪ x‬جميع األرقام السداسية اليت تليها ؛‬ ‫•‬
‫فيمثل "\ ‪ "x1234‬حر ًفا واح ًدا من ‪ 16‬بت يتكون من البتات املقابلة لهذه األرقام السدايس‪-‬عرش األربعة‪.‬‬ ‫•‬
‫ونظرًا ألن معظم األجهزة تحتوي على أحرف ‪ 8‬بت ‪ ،‬فمن غري املحتمل أن تكون هذه القيم مفيدة‪.‬‬ ‫•‬
‫في العادة ‪ ،‬يتم استخدام األحرف السداسية العرشية اليت تحتوي على أكرث من ‪ 8‬بتات ‪،‬‬ ‫•‬
‫مع مجموعات األحرف املمتدة باستخدام إحدى الرموز البادئة من جدول ‪.2.2‬‬ ‫•‬

‫تحديد نوع الحرفي‬


‫‪Specifying the Type of a Literal‬‬

‫يمكننا تجاوز النوع االفرتايض لحرفية عدد صحيح أو فاصلة عرشية أو أحرف ‪،‬‬
‫من خالل توفري الحقة أو بادئة كما سبق وذكرنا في الجدول ‪.2.2‬‬ ‫•‬

‫'‪L'a‬‬ ‫‪//wide character literal, type is wchar_t‬‬


‫"!‪u8"hi‬‬ ‫)‪//utf-8 string literal (utf-8 encodes Unicode character in 8 bits‬‬
‫‪42ULL‬‬ ‫‪// unsigned integer literal, type is unsigned long long‬‬
‫‪1E-3F‬‬ ‫‪// single-precision floating-point literal, type is float‬‬
‫‪3.14159L // extended-precision floating-point literal, type is long double‬‬

‫أفضل ممارسة‬
‫عندما تكتب حرفية قيمة طويلة ‪ ، 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‬بال_إشارة‪.‬‬ ‫•‬

‫حرفيات املنطقي واملؤرش‬


‫‪Boolean and Pointer Literals‬‬

‫الكلمتان ‪ true‬صحيح و ‪ false‬خطأ‪ :‬هما حرفيتا نوع املنطق ‪: bool‬‬

‫;‪bool test = false‬‬

‫أما الكلمة ‪ nullptr‬عبارة عن حرفية مؤرش‪ .‬سيكون لدينا املزيد لنقوله عن املؤرشات و ‪ nullptr‬ﻻحقاً‪.‬‬

‫قسم التمارين ‪2.1.3‬‬

‫تمرين ‪: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‬‬

‫يستخدم تعريف ‪ book‬نوع مكتبة ‪.std::string‬‬


‫مثل قناة املدخالت واملخرجات ‪ ، iostream‬يتم تعريف السلسلة في مساحة االسم ‪.std‬‬ ‫•‬
‫سيكون لدينا املزيد لنقوله عن نوع السلسلة في الفصل الثالث‪.‬‬ ‫•‬
‫في الوقت الحالي ‪ ،‬ما هو مفيد أن نعرفه هو أن السلسلة نوع يمثل تسلسال متغري الطول من األحرف‪.‬‬ ‫•‬
‫تعطينا مكتبة السالسل عدة طرق لتهيئة كائناتها‪.‬‬ ‫•‬
‫إحدى هذه الطرق هي أن تكون نسخة من حرفية سلسلة‪.‬‬ ‫•‬
‫وبهذا تمت تهيئة ‪ book‬لتحمل األحرف "‪."X-78345-201-0‬‬ ‫•‬
‫ما هو الكائن ‪Object‬؟‬ ‫مصطلحات‪:‬‬

‫يميل مربمجو يس‪ ++‬إلى أن يكونوا متعجرفني في استخدامهم ملصطلح الكائن‪.‬‬ ‫•‬
‫بشكل عام ‪،‬يعترب الكائن منطقة من الذاكرة يمكن أن تحتوي على بيانات ولها نوع‪.‬‬ ‫•‬

‫يستخدم البعض مصطلح كائن فقط لإلشارة إلى متغريات أو قيم أنواع فئة‪.‬‬ ‫•‬
‫يمزي البعض اآلخر بني كائنات مسماة وغري مسماة ‪،‬‬ ‫•‬
‫باستخدام املصطلح متغري ‪ Variable‬ليشري إلى الكائنات املسماة‪.‬‬ ‫•‬
‫ال يزال البعض اآلخر يمزي بني الكائنات والقيم ‪،‬‬ ‫•‬
‫باستخدام املصطلح كائن ‪ Object‬للبيانات اليت يمكن تغيريها بواسطة برنامج‪،‬‬ ‫•‬
‫واستخدام املصطلح قيمة ‪ Value‬للبيانات اليت تكون للقراءة فقط‪.‬‬ ‫•‬

‫في هذا الكتاب ‪ ،‬سنتبع االستخدام األكرث عمومية بأن الكائن ‪ Object‬هو منطقة من الذاكرة لها نوع‪.‬‬ ‫•‬
‫سنستخدم املصطلح كائن ‪ Object‬بحرية بغض النظر ‪،‬‬ ‫•‬
‫عما إذا كان الكائن يحتوي على نوع مدمج أو نوع فئة ‪،‬‬ ‫•‬
‫أو مسمى أو غري مسمى ‪ ،‬أو يمكن قراءته أو كتابته‪.‬‬ ‫•‬

‫املهيئات‬
‫‪Initializers‬‬

‫يحصل كل كائن يتم تهيئته على قيمة محددة في لحظة إنشائه‪.‬‬


‫يمكن للقيم املستخدمة في تهيئة متغري أن تكون تعبريات معقدة بشكل تعسفي‪.‬‬ ‫•‬
‫مرئيا على الفور‪.‬‬
‫ً‬ ‫عندما يعرف تعريف متغريين أو أكرث ‪ ،‬يصبح اسم كل كائن‬ ‫•‬
‫وبالتالي ‪ ،‬من املمكن تهيئة متغري على قيمة ما تم تعريفها مسب ًقا في نفس التعريف‪.‬‬ ‫•‬

‫وتكرارا‪.‬‬
‫ً‬ ‫مرارا‬
‫ً‬ ‫التهيئة في يس‪ ++‬موضوع معقد بشكل مدهش وسنعود إليه‬
‫يتم الخلط بني العديد من املربمجني في استخدام الرمز = لتهيئة متغري‪.‬‬ ‫•‬
‫من املغري التفكري في التهيئة كشكل من أشكال التعيني ‪ ،‬إﻻ أنهما عمليتان مختلفتان في يس‪.++‬‬ ‫•‬
‫هذا املفهوم محري بشكل خاص ألنه في العديد من اللغات يكون التميزي غري ذي صلة ويمكن تجاهله‪.‬‬ ‫•‬
‫غالبا ما يكون التميزي غري مهم‪ .‬ومع ذلك ‪،‬‬
‫ً‬ ‫عالوة على ذلك ‪ ،‬حىت في يس‪، ++‬‬ ‫•‬
‫فهو مفهوم أسايس وسنكرره خالل الكتاب‪.‬‬ ‫•‬

‫تحذير‬
‫التهيئة ليست هي التعيني‪.‬‬
‫تحدث التهيئة عندما يتم إعطاء متغري قيمة ما عند إنشائه‪.‬‬ ‫•‬
‫بينما يطمس التعيني القيمة الحالية للكائن ويستبدل تلك القيمة بقيمة جديدة‪.‬‬ ‫•‬
‫تهيئة القائمة‬
‫‪List Initialization‬‬

‫موضوعا معق ًدا هو أن اللغة تعرف عدة صيغ مختلفة من التهيئة‪.‬‬


‫ً‬ ‫إحدى الطرق اليت تكون فيها التهيئة‬
‫فمثالً ‪ ،‬يمكننا استخدام إحدى الطرق األربعة املختلفة التالية ‪،‬‬ ‫•‬
‫لتعريف متغري عدد صحيح ‪ int‬يسمى ‪ unit_sold‬وتهيئته على ‪:0‬‬ ‫•‬

‫;‪int units_sold = 0‬‬ ‫;)‪int units_sold (0‬‬


‫;}‪int units_sold {0‬‬ ‫;}‪int units_sold = {0‬‬

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

‫;‪long double ld = 3.1415926536‬‬


‫;}‪int a{ld}, b = {ld‬‬ ‫‪// error: narrowing conversion required‬‬
‫= ‪int c(ld), d‬‬ ‫; ‪ld‬‬ ‫‪// ok: but value will be truncated‬‬

‫يرفض املرتجم تهيئة ‪ a‬و ‪، b‬‬ ‫•‬


‫وذلك ألن استخدام قيمة مزدوج طويل لتهيئة عدد صحيح من املحتمل أن يفقد بيانات‪.‬‬ ‫•‬
‫بحد أدنى ‪ ،‬سيتم اقتطاع الجزء الكرسي من ‪.ld‬‬ ‫•‬
‫إضافة إلى ذلك ‪ ،‬قد يكون الجزء الصحيح في ‪ ld‬أكرب من أن يتناسب مع عدد صحيح‪.‬‬ ‫•‬

‫وكما هو معروض هنا ‪ ،‬فقد يبدو التميزي تافهاً ‪-‬‬


‫بعد كل يشء ‪ ،‬من غري املرجح أن نقوم مبارشة بتهيئة عدد صحيح على مزدوج طويل‪.‬‬ ‫•‬
‫ومع ذلك ‪ ،‬كما سرنى في الفصل ‪ ، 16‬قد تحدث مثل هذه التهيئة عن غري قصد‪.‬‬ ‫•‬
‫سنقول املزيد عن هذه األشكال من التهيئة في الفقرة ‪ 3.2.1‬والفقرة ‪ 3.3.1‬ﻻحقا‪.‬‬ ‫•‬

‫التهيئة اﻻفرتاضية‬
‫‪Default Initialization‬‬

‫افرتاضيا‪.‬‬
‫ً‬ ‫مهيِـئ ‪ ،‬يتم تهيئة املتغري‬
‫عندما نعرف متغريًا بدون ّ‬
‫• مثل هذه املتغريات تعطي قيمة "افرتاضية"‪.‬‬
‫أيضا على مكان تعريف املتغري‪.‬‬
‫تعتمد القيمة االفرتاضية على نوع املتغري وقد تعتمد ً‬ ‫•‬

‫تعتمد قيمة كائن من نوع مدمج لم تتم تهيئته بشكل رصيح على مكان تعريفه‪.‬‬
‫فيتم تهيئة املتغريات املعرفة خارج أي بنية دالة على الصفر‪ .‬باستثناء واحد ‪ ،‬سنغطيه في الفقرة ‪، 6.1.1‬‬ ‫•‬
‫تكون متغريات النوع املدمج املعرفة داخل دالة غري مهيأة‪.‬‬ ‫•‬
‫معرف‪.‬‬
‫قيمة متغري غري مهيأ من النوع املدمج يعطي سلوكاً غري ّ‬ ‫•‬
‫معرفة‪.‬‬
‫ومن الخطأ نسخ أو محاولة الوصول إلى قيمة متغري تكون قيمته غري ّ‬ ‫•‬

‫تتحكم كل فئة في كيفية تهيئة كائنات نوعها‪.‬‬


‫مهيِـئ‪.‬‬
‫على وجه الخصوص ‪ ،‬األمر مرتوك للفئة فيما إذا كان بإمكاننا تعريف كائنات ذلك النوع بدون ّ‬ ‫•‬
‫إذا كان باﻹمكان ‪ ،‬تحدد الفئة أي قيمة قد يحتويها الكائن الناتج‪.‬‬ ‫•‬
‫وتسمح معظم الفئات بتعريف الكائنات بدون مهيئات رصيحة‪.‬‬ ‫•‬
‫توفر مثل تلك الفئات قيمة افرتاضية مناسبة لنا‪.‬‬ ‫•‬

‫مثالً ‪ ،‬وكما رأينا للتو ‪ ،‬تقول فئة مكتبة السلسلة أنه إذا لم نوفر ُمهيًئ ا ‪ ،‬فإن السلسلة الناتجة سلسلة فارغة‪:‬‬

‫‪std::string empty; // empty implicitly initialized to empty string‬‬


‫;‪Sales_item item‬‬ ‫‪// default-initialized Sales_item object‬‬

‫تتطلب بعض الفئات أن يتم تهيئة كل كائن بشكل رصيح‪.‬‬ ‫•‬


‫مهيِـئ‪.‬‬
‫سيشتكي املرتجم إذا حاولنا إنشاء كائن من تلك الفئة بدون ّ‬ ‫•‬

‫ملحوظة‬
‫الكائنات غري املهيأة من النوع املدمج واملعرفة داخل بنية دالة قيمتها غري معرفة‪.‬‬
‫الكائنات من نوع الفئة اليت ال نقوم بتهيئتها رصاحة قيمتها تعرف عن طريق الفئة‪.‬‬

‫تمارين القسم ‪2.2.1‬‬

‫تمرين ‪:2.9‬‬
‫‪ -‬ارشح التعاريف التالية‪.‬‬
‫‪ -‬بالنسبة لتلك اليت تعترب غري رشعية ‪ ،‬ارشح ما هو الخطأ وكيفية تصحيحه‪.‬‬

‫;‪(a) std::cin >> int input_value‬‬


‫;} ‪(b) int i = { 3.14‬‬
‫;‪(c) double salary = wage = 9999.99‬‬
‫;‪(d) int i = 3.14‬‬
‫تمرين ‪:2.10‬‬
‫‪ -‬ما هي القيم األولية ‪ ،‬إن وجدت ‪ ،‬لكل من املتغريات التالية؟‬
‫;‪std::string global_str‬‬
‫;‪int global_int‬‬
‫)(‪int main‬‬
‫{‬
‫;‪int local_int‬‬
‫;‪std::string local_str‬‬
‫}‬

‫‪ 2٫2٫2‬املتغريات إعالنات وتعريفات‬


‫‪2.2.2. Variable Declarations & Definitions‬‬

‫عموما بالتجميع املنفصل‪.‬‬


‫ً‬ ‫للسماح لكتابة الربامج بأجزاء منطقية ‪ ،‬تدعم لغة يس‪ ++‬ما يُعرف‬
‫• يتيح لنا التجميع املنفصل تقسيم برامجنا إلى عدة ملفات ‪ ،‬يمكن تجميع كل منها بشكل مستقل‪.‬‬

‫برنامجا إلى عدة ملفات ‪،‬‬


‫ً‬ ‫عندما نفصل‬
‫نحتاج إلى طريقة ملشاركة اﻷكواد الربمجية عرب هذه امللفات‪.‬‬ ‫•‬
‫على سبيل املثال ‪ ،‬قد تحتاج اﻷكواد الربمجية املحددة في ملف ما إلى استخدام متغري معرف في ملف آخر‪.‬‬ ‫•‬
‫وكمثال ملموس ‪ ،‬فكر في ‪ std::cout‬و ‪.std::cin‬‬ ‫•‬
‫لقد كانت كائنات معرفة في مكان ما من املكتبة القياسية ‪ ،‬ومع ذلك أمكن لربامجنا استخدام تلك الكائنات‪.‬‬ ‫•‬

‫املتغريات غري املهيأة تسبب مشاكل وقت التشغيل‬ ‫احذر‪:‬‬

‫معرفة‪.‬‬
‫املتغري غري املهيأ يحمل قيمة غري ّ‬ ‫•‬
‫غالبا تصحيحه‪ .‬عالوة على ذلك ‪،‬‬
‫ً‬ ‫تعد محاولة استخدام قيمة متغري غري مهيأ خطأ يصعب‬ ‫•‬
‫ال يُطلب من املرتجم اكتشاف مثل هذه األخطاء ‪،‬‬ ‫•‬
‫بالرغم من أن معظمها ستحذر على األقل من بعض استخدامات املتغريات غري املهيأة‪.‬‬ ‫•‬

‫ما يحدث عندما نستخدم متغريًا غري مهيأ هو سلوك غري معرف‪.‬‬ ‫•‬
‫أحياناً ‪ ،‬نكون محظوظني ويتعطل برنامجنا بمجرد وصولنا إلى الكائن‪.‬‬ ‫•‬
‫بمجرد أن نتعقب موقع االنهيار ‪ ،‬فمن السهل عادة رؤية أن املتغري لم تتم تهيئته بشكل صحيح‪.‬‬ ‫•‬
‫بينما في أوقات أخرى ‪ ،‬يكتمل الربنامج ولكن ينتج عنه نتائج خاطئة‪.‬‬ ‫•‬
‫واألسوأ من ذلك ‪ ،‬قد تظهر النتائج صحيحة في تشغيل ما لربنامجنا ولكنها تفشل في تشغيل الحق‪.‬‬ ‫•‬

‫عالوة على ذلك ‪ ،‬فإن إضافة كود إلى الربنامج في مكان غري ذي صلة ‪...‬‬ ‫•‬
‫يمكن أن يؤدي إلى ما اعتقدنا أنه برنامج صحيح يبدأ إنتاج نتائج خاطئة‪.‬‬ ‫•‬
‫تلميح‬

‫دائما ‪ ،‬ولكن‬
‫ً‬ ‫نويص بتهيئة كل كائن نوع مدمج‪ .‬ليس من الرضوري‬
‫املهيِـئ‪.‬‬
‫ّ‬ ‫مهيِـئ حىت يمكنك التأكد من أنه من اآلمن حذف‬
‫من األسهل واألكرث أما ًنا توفري ّ‬

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

‫رصيحا‪:‬‬
‫ً‬ ‫أيضا ‪ ،‬نضيف كلمة ‪ extern‬األساسية وقد ال نقدم ُمهيًئ ا‬
‫للحصول على إعالن ﻻ يعد تعري ًفا ً‬

‫;‪extern int i‬‬ ‫‪// declares but does not define I‬‬
‫;‪int j‬‬ ‫‪// declares and defines j‬‬

‫رصيحا يعترب تعريفاً‪.‬‬


‫ً‬ ‫أي إعالن يتضمن ُمهيًئ ا‬
‫عرف على أنه ‪ ، extern‬لكن القيام بذلك يلغي ‪.extern‬‬ ‫مهيِـئ ملتغري ُم َّ‬
‫• يمكننا توفري ّ‬

‫مهيِـئ عبارة عن تعريف‪:‬‬


‫يحتوي ‪ extern‬على ّ‬

‫‪extern double pi = 3.1416; // definition‬‬

‫مهيِـئ على ‪ extern‬داخل دالة‪.‬‬


‫من الخطأ توفري ّ‬

‫ملحوظة‬
‫يتوجب تعريف املتغريات مرة واحدة فقط لكن يمكن اإلعالن عنها عدة مرات‪.‬‬

‫غامضا في هذه املرحلة ولكنه مهم في الواقع‪.‬‬


‫ً‬ ‫قد يبدو التميزي بني اإلعالن والتعريف‬
‫استخدام متغري في أكرث من ملف يتطلب إعالنات منفصلة عن تعريف املتغري‪.‬‬ ‫•‬
‫نعرف هذا املتغري في ملف واحد فقط‪.‬‬
‫الستخدام نفس املتغري في ملفات متعددة ‪ ،‬يجب أن ّ‬ ‫•‬
‫تعرفه ‪.-‬‬
‫يجب أن تعلن امللفات األخرى عن املتغري الذي تستخدمه – دون أن ّ‬ ‫•‬
‫سيكون لدينا املزيد لنقوله حول كيفية دعم يس‪ ++‬للرتجمة املنفصلة في الفقرة ‪ 2.6.3‬والفقرة ‪. 6.1.3‬‬ ‫•‬

‫تمارين القسم ‪2.2.2‬‬


‫التمرين ‪:2.11‬‬
‫‪ -‬ارشح ما إذا كان كل مما يلي إعال ًنا أم تعري ًفا‪:‬‬
‫;‪(a) extern int ix = 1024‬‬
‫;‪(b) int iy‬‬
‫;‪(c) extern int iz‬‬

‫النوع الساكن ‪Static Typing‬‬ ‫مفهوم أسايس‪:‬‬

‫يس‪ ++‬هي لغة مكتوبة بشكل ساكن ‪ ،‬ما يعين أنه يتم فحص األنواع في وقت الرتجمة‪.‬‬ ‫•‬
‫يشار إلى العملية اليت يتم من خاللها فحص األنواع باسم فحص النوع ‪.type checking‬‬ ‫•‬

‫كما رأينا ‪ ،‬فإن نوع الكائن يقيد العمليات اليت يمكن أن يؤديها الكائن‪.‬‬ ‫•‬
‫في يس‪ ، ++‬يتحقق املرتجم ما إذا كانت العمليات اليت نكتبها مدعومة من قبل األنواع اليت نستخدمها‪.‬‬ ‫•‬
‫فإذا حاولنا القيام بأشياء ال يدعمها النوع ‪،‬‬ ‫•‬
‫سيقوم املرتجم بإنشاء رسالة خطأ وال ينتج مل ًفا قابالً للتنفيذ‪.‬‬ ‫•‬

‫ومع ازدياد تعقيد برامجنا ‪ ،‬سرنى أن فحص النوع الساكن يمكن أن يساعد في العثور على األخطاء‪.‬‬ ‫•‬
‫مع ذلك ‪ ،‬فإن أهمية الفحص الساكن هي أن نوع كل كيان نستخدمه يجب أن يعرفه املرتجم‪.‬‬ ‫•‬
‫كمثال ‪ ،‬يجب أن نعلن عن نوع املتغري قبل أن نتمكن من استخدامه‪.‬‬ ‫•‬

‫‪ 2٫2٫3‬املعرفات‬
‫‪2.2.3. Identifiers‬‬

‫يمكن أن تتكون املعرفات في يس‪ ++‬من أحرف وأرقام ورشطة سفلية‪.‬‬


‫لن تفرض اللغة ح ًدا على طول االسم‪.‬‬ ‫•‬
‫لكن يجب أن تبدأ املعرفات إما بحرف أو برشطة سفلية‪.‬‬ ‫•‬

‫املعرفات حساسة لحالة األحرف ؛ فاألحرف الكبرية والصغرية متمزية‪:‬‬

‫‪// defines four different int variables‬‬


‫;‪int somename, someName, SomeName, SOMENAME‬‬

‫تحتفظ اللغة بمجموعة من األسماء املدرجة في الجدولني ‪ 2.3‬والجدول ‪ 2.4‬الستخدامها الخاص‪.‬‬


‫ال يسمح باستخدام هذه األسماء كمعرفات‪.‬‬
‫الجدول ‪ .2.3‬كلمات يس‪++‬‬

‫‪alignas‬‬ ‫‪continue‬‬ ‫‪friend‬‬ ‫‪register‬‬ ‫‪true‬‬


‫‪alignof‬‬ ‫‪decltype‬‬ ‫‪goto‬‬ ‫‪reinterpret_cast‬‬ ‫‪try‬‬
‫‪asm‬‬ ‫‪default‬‬ ‫‪if‬‬ ‫‪return‬‬ ‫‪typedef‬‬
‫‪auto‬‬ ‫‪delete‬‬ ‫‪inline‬‬ ‫‪short‬‬ ‫‪typeid‬‬
‫‪bool‬‬ ‫‪do‬‬ ‫‪int‬‬ ‫‪signed‬‬ ‫‪typename‬‬
‫‪break‬‬ ‫‪double‬‬ ‫‪long‬‬ ‫‪sizeof‬‬ ‫‪union‬‬
‫‪case‬‬ ‫‪dynamic_cast‬‬ ‫‪mutable‬‬ ‫‪static‬‬ ‫‪unsigned‬‬
‫‪catch‬‬ ‫‪else‬‬ ‫‪namespace‬‬ ‫‪static_assert‬‬ ‫‪using‬‬
‫‪char‬‬ ‫‪enum‬‬ ‫‪new‬‬ ‫‪static_cast‬‬ ‫‪virtual‬‬
‫‪char16_t‬‬ ‫‪explicit‬‬ ‫‪noexcept‬‬ ‫‪struct‬‬ ‫‪void‬‬
‫‪char32_t‬‬ ‫‪export‬‬ ‫‪nullptr‬‬ ‫‪switch‬‬ ‫‪volatile‬‬
‫‪class‬‬ ‫‪extern‬‬ ‫‪operator‬‬ ‫‪template‬‬ ‫‪wchar_t‬‬
‫‪const‬‬ ‫‪false‬‬ ‫‪private‬‬ ‫‪this‬‬ ‫‪while‬‬
‫‪constexpr‬‬ ‫‪float‬‬ ‫‪protected‬‬ ‫‪thread_local‬‬
‫‪const_cast‬‬ ‫‪for‬‬ ‫‪public‬‬ ‫‪throw‬‬

‫الجدول ‪ .2.4‬أسماء عوامل يس‪ ++‬البديلة‬

‫‪and‬‬ ‫‪bitand‬‬ ‫‪compl‬‬ ‫‪not_eq‬‬ ‫‪or_eq‬‬ ‫‪xor_eq‬‬


‫‪and_eq‬‬ ‫‪bitor‬‬ ‫‪not‬‬ ‫‪or‬‬ ‫‪xor‬‬

‫أيضا بمجموعة من األسماء الستخدامها في املكتبة القياسية‪.‬‬


‫يحتفظ املعيار ً‬
‫ال يسمح أن تحتوي املعرفات اليت نعرفها في برامجنا على رشطتني سفليتني متتاليتني ‪،‬‬ ‫•‬
‫وال يمكن أن يبدأ املعرف برشطة سفلية متبوعة مبارشة بحرف كبري‪.‬‬ ‫•‬
‫إضافة إلى ذلك ‪ ،‬ال يسمح أن تبدأ املعرفات املعرفة خارج دالة برشطة سفلية‪.‬‬ ‫•‬

‫اصطالحات اﻷسماء املتغرية‬


‫‪Conventions for Variable Names‬‬

‫عموما لتسمية املتغريات‪.‬‬


‫ً‬ ‫هناك عدد من االصطالحات املقبولة‬
‫• يمكن أن يؤدي اتباع هذه االصطالحات إلى تحسني إمكانية قراءة الربنامج‪.‬‬
‫املعرف إشارات إلى معناه‪.‬‬
‫ّ‬ ‫يجب أن يعطي‬ ‫•‬
‫تتكون أسماء املتغريات عادة من أحرف صغرية ‪ index -‬وليس ‪ Index‬أو ‪.INDEX‬‬ ‫•‬
‫مثل عنرص املبيعات ‪ ، Sales_item‬تبدأ الفئات اليت نعرفها عاد ًة بحرف كبري‪.‬‬ ‫•‬
‫برصيا كل كلمة برشطة سفلية أو حرف كبري ألول حرف ‪،‬‬
‫ً‬ ‫يجب أن تمزي املعرفات ذات الكلمات املتعددة‬ ‫•‬
‫على سبيل املثال ‪ student_loan ،‬أو ‪ ، studentLoan‬وليس ‪.studentloan‬‬ ‫•‬

‫من أفضل املمارسات‬


‫تكون اصطالحات التسمية مفيدة للغاية عند اتباعها باستمرار‪.‬‬
‫قسم التدريبات ‪2.2.3‬‬

‫التمرين ‪: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‬‬

‫في أي نقطة معينة في الربنامج ‪،‬‬


‫يشري كل اسم قيد االستخدام إلى كيان محدد ‪ -‬متغري أو دالة أو نوع ‪...‬إلخ‪.‬‬ ‫•‬
‫مع ذلك ‪ ،‬يمكن إعادة استخدام اسم معني لإلشارة إلى كيانات مختلفة في نقاط مختلفة من الربنامج‪.‬‬ ‫•‬
‫النطاق ‪ Scope‬هو جزء من الربنامج يكون لالسم فيه معىن معني‪.‬‬ ‫•‬
‫يتم تحديد معظم النطاقات في يس‪ ++‬بأقواس مجعدة‪.‬‬ ‫•‬
‫يمكن أن يشري االسم نفسه إلى كيانات مختلفة في نطاقات مختلفة‪.‬‬ ‫•‬
‫تكون األسماء مرئية من النقطة اليت تم اإلعالن عنها فيها حىت نهاية النطاق الذي يظهر فيه اإلعالن‪.‬‬ ‫•‬

‫على سبيل املثال ‪ ،‬ضع في اعتبارك الربنامج من الفقرة ‪: 1.4.2‬‬

‫>‪#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‬‬

‫يعرف هذا الربنامج ثالثة أسماء ‪ main -‬و ‪ sum‬و ‪- val‬‬


‫ّ‬ ‫•‬
‫ويستخدم اسم مساحة االسم ‪ ، std‬إلى جانب اسمني من مساحة االسم تلك — ‪ cout‬و ‪.endl‬‬ ‫•‬
‫يتم تعريف االسم ‪ main‬خارج أي أقواس معقوفة‪.‬‬ ‫•‬
‫االسم ‪ - main‬مثل معظم األسماء املعرفة خارج دالة ‪ -‬له نطاق عام‪.‬‬ ‫•‬
‫وبمجرد اإلعالن ‪ ،‬يمكن الوصول إلى األسماء على النطاق العام في جميع أنحاء الربنامج‪.‬‬ ‫•‬
‫يتم تعريف االسم ‪ sum‬داخل نطاق كتلة بنية دالة ‪.main‬‬ ‫•‬
‫ويمكن الوصول إليه من نقطة إعالنها طوال بقاء دالة ‪ main‬ولكن ليس خارجها‪.‬‬ ‫•‬
‫أما املتغري ‪ sum‬فله نطاق كتلة‪.‬‬ ‫•‬
‫تم تعريف اسم ‪ val‬في نطاق جملة ‪.for‬‬ ‫•‬
‫ويمكن استخدامه داخل هذه الجملة ولكن ليس في أي مكان آخر بشكل رئييس‪.‬‬ ‫•‬

‫نصيحة ‪ :‬عرف املتغريات حيث تستخدمها ألول مرة‬

‫‪Define Variables Where You First Use Them‬‬

‫من الجيد عاد ًة تعريف كائن بالقرب من النقطة اليت تم استخدام الكائن عندها ألول مرة‪.‬‬ ‫•‬
‫يؤدي القيام بذلك إلى تحسني قابلية القراءة من خالل تسهيل العثور على تعريف املتغري‪.‬‬ ‫•‬
‫غالبا ما يكون من األسهل إعطاء املتغري قيمة أولية مفيدة ‪،‬‬
‫ً‬ ‫واألهم من ذلك ‪ ،‬أنه‬ ‫•‬
‫عندما يتم تعريف املتغري بالقرب من مكان استخدامه ألول مرة‪.‬‬ ‫•‬

‫النطاقات املتداخلة‬
‫‪Nested Scopes‬‬

‫يمكن أن تحتوي النطاقات على نطاقات أخرى‪.‬‬


‫يشار إلى النطاق املتداخل على أنه نطاق داخلي ‪،inner scope‬‬ ‫•‬
‫ويشار إلى النطاق املحتوي بالنطاق الخارجي ‪.outer scope‬‬ ‫•‬

‫بمجرد اإلعالن عن اسم في النطاق ‪،‬‬


‫يمكن استخدام هذا االسم بواسطة النطاقات املتداخلة داخل هذا النطاق‪.‬‬ ‫•‬
‫أيضا إعادة تعريف األسماء املعلنة في النطاق الخارجي في نطاق داخلي‪:‬‬
‫يمكن ً‬ ‫•‬

‫>‪#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.2.4‬‬

‫تمرين ‪: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.3. Compound Types‬‬

‫النوع املركب هو نوع معرف بمصطلحات نوع آخر‪.‬‬


‫يحتوي يس‪ ++‬على العديد من األنواع املركبة ‪،‬‬ ‫•‬
‫سنغطي في هذا الفصل اثنني منها ‪ -‬املراجع ‪ references‬واملؤرشات ‪.– pointers‬‬ ‫•‬

‫يعد تعريف متغريات من النوع املركب من أكرث التعريفات اليت رأيناها تعقي ًدا حىت اآلن‪.‬‬
‫فقد قلنا في الفقرة ‪ 2.2‬أن اإلعالنات البسيطة تتكون من نوع يتبعه قائمة بأسماء املتغريات‪.‬‬ ‫•‬
‫متبوعا بقائمة من اإلعالنات‪.‬‬
‫ً‬ ‫أساسيا‬
‫ً‬ ‫نوعا‬
‫بشكل عام ‪ ،‬يعترب اإلعالن ً‬ ‫•‬
‫مرتبطا بالنوع األسايس‪.‬‬
‫ً‬ ‫نوعا‬
‫يقوم كل إعالن بتسمية متغري ويعطي املتغري ً‬ ‫•‬

‫معرفات ليست أكرث من أسماء متغرية‪.‬‬


‫اإلعالنات اليت رأيناها حىت اآلن لها ّ‬
‫نوع تلك املتغريات هو النوع األسايس لإلعالن‪.‬‬ ‫•‬
‫تُحدد املُع ِلنات األكرث تعقي ًدا املتغريات ذات األنواع املركبة اليت يتم إنشاؤها من النوع األسايس لإلعالن‪.‬‬ ‫•‬

‫‪ 2٫3٫1‬املراجع‬
‫‪2.3.1. References‬‬

‫ملحوظة‬
‫قدم املعيار الجديد نوع مرجع جديد ‪ rvalue reference“ :‬مرجع قيمة يمىن” ‪،‬‬ ‫•‬
‫سنغطيه في الفقرة ‪.13.6.1‬‬ ‫•‬
‫تلك املراجع مخصصة بشكل أسايس لالستخدام داخل الفئات ‪.classes‬‬ ‫•‬
‫أما إذا تحدثنا فنياً ‪ :‬عندما نستخدم مصطلح املرجع ‪،‬‬ ‫•‬
‫فإننا نعين "‪ lvalue reference‬مرجع قيمة يرسى"‪.‬‬ ‫•‬

‫اسما بديالً لكائن‪ .‬نوع املرجع "يشري إلى" نوع آخر‪.‬‬


‫ً‬ ‫يعرف املرجع‬
‫ّ‬

‫نعرف نوع املرجع من خالل كتابة ُمع ِلن على شكل ‪ ، &d‬حيث يكون ‪ d‬هو االسم الذي يتم اإلعالن عنه‪:‬‬
‫ّ‬

‫;‪int ival = 1024‬‬


‫;‪int &refVal = ival‬‬ ‫‪// refVal refers to (is another name for) ival‬‬
‫;‪int &refVal2‬‬ ‫‪// error: a reference must be initialized‬‬

‫في العادة ‪،‬‬


‫املهيِـئ على الكائن الذي نقوم بإنشائه‪.‬‬
‫ّ‬ ‫عندما نقوم بتهيئة متغري ‪ ،‬يتم نسخ قيمة‬ ‫•‬
‫بمهيِـئه‪.‬‬
‫ّ‬ ‫املهيِـئ ‪ ،‬فإننا نربط املرجع‬
‫مرجعا ‪ ،‬فبدال ً من نسخ قيمة ّ‬
‫ً‬ ‫نعرف‬
‫لكن عندما ّ‬ ‫•‬
‫مرتبطا بكائنه األولي‪.‬‬
‫ً‬ ‫وبمجرد التهيئة ‪ ،‬يظل املرجع‬ ‫•‬
‫فال توجد طريقة إلعادة إنشاء مرجع لإلشارة إلى كائن مختلف‪.‬‬ ‫•‬
‫ونظرًا لعدم وجود طريقة إلعادة ربط مرجع ‪ ،‬يجب تهيئة املراجع (بإعطائها قيمة عند إنشاءها)‪.‬‬ ‫•‬

‫املرجع ما هو إﻻ اسم مستعار‬


‫‪A Reference Is an Alias‬‬

‫ملحوظة‬
‫املرجع ليس كائنًا‪ .‬بالعكس ‪ ،‬املرجع هو مجرد اسم آخر لكائن موجود بالفعل‪.‬‬

‫بعد تعريف مرجع ‪ ،‬فإن جميع العمليات على هذا املرجع تعترب في الواقع عمليات على الكائن املرتبط به؛‬

‫;‪refVal = 2‬‬ ‫‪// assigns 2 to object to which refVal refers, to ival‬‬


‫‪int ii = refVal; // same as ii = ival‬‬

‫فعندما نعني على مرجع ‪ ،‬فإننا نعني على الكائن املرتبط باملرجع‪.‬‬ ‫•‬
‫وعندما نجلب قيمة مرجع ‪ ،‬فإننا بالفعل نجلب قيمة الكائن املرتبط باملرجع‪.‬‬ ‫•‬
‫كمهيِـئ ‪ ،‬فإننا بالفعل نستخدم الكائن الذي يرتبط به املرجع ‪:‬‬
‫ّ‬ ‫مرجعا‬
‫ً‬ ‫وباملثل ‪ ،‬عندما نستخدم‬ ‫•‬

‫‪// 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‬‬ ‫•‬
‫ﻻ يرتبط املرجع إﻻ بكائن ‪ ،‬وليس بقيمته الحرفية أو نتيجة تعبري أكرث عمومية ‪:‬‬ ‫•‬

‫‪int‬‬ ‫;‪&refVal4 = 10‬‬ ‫‪// error: initializer must be object‬‬


‫‪double dval‬‬ ‫;‪= 3.14‬‬
‫‪int‬‬ ‫;‪&refVal5 = dval‬‬ ‫‪// error: initializer must be int object‬‬

‫قسم التدريبات ‪2.3.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‬‬

‫املؤرش هو نوع مركب "يشري إلى" نوع آخر‪.‬‬


‫مثل املراجع ‪ ،‬تُستخدم املؤرشات للوصول غري املبارش إلى كائنات أخرى‪.‬‬ ‫•‬
‫وعلى عكس املرجع ‪ ،‬فإن املؤرش هو كائن في حد ذاته‪.‬‬ ‫•‬
‫يمكن تعيني املؤرشات ونسخها ؛ فيمكن ملؤرش واحد أن يشري إلى عدة كائنات مختلفة على مدار حياته‪.‬‬ ‫•‬
‫لكن على عكس املرجع ‪ ،‬ال يلزم تهيئة املؤرش بإعطائه قيمة في وقت تعريفه‪.‬‬ ‫•‬
‫املعرفة في نطاق كتلة لها قيمة غري معلومة إذا لم تتم تهيئتها‪.‬‬
‫ّ‬ ‫ومثل األنواع املدمجة األخرى ‪ ،‬فاملؤرشات‬ ‫•‬

‫تحذير‬
‫غالب ا ما يصعب فهم املؤرشات‪ .‬مشاكل التصحيح بسبب أخطاء املؤرش تربك حىت املربمجني ذوي الخربة‪.‬‬
‫ً‬

‫معرف على شكل ‪ ، *d‬حيث ‪ d‬هو االسم الذي يتم تعريفه‪.‬‬


‫نعرف نوع مؤرش من خالل كتابة ّ‬

‫يجب تكرار * لكل متغري مؤرش‪:‬‬

‫‪int‬‬ ‫;‪*ip1, *ip2‬‬ ‫‪// both ip1 and ip2 pointers to int‬‬
‫‪double‬‬ ‫;‪dp, *dp2‬‬ ‫‪// dp2 pointer to double; dp double‬‬

‫أخذ عنوان كائن‬


‫‪Taking the Address of an Object‬‬

‫يحمل مؤرش ما عنوان كائن آخر‪ .‬حيث نحصل على عنوان كائن عن طريق عامل العنوان (&) ‪:‬‬

‫;‪int ival = 42‬‬


‫;‪int *p = &ival‬‬ ‫‪// p holds address of ival; p pointer to ival‬‬

‫تُع ِّرف الجملة الثانية ‪ 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‬يمكن أن يكون غري صالح‪ .‬القيم األخرى غري الثالثة السابقة غري صالحة‪.‬‬

‫من الخطأ نسخ أو محاولة الوصول إلى قيمة مؤرش غري صالح‪.‬‬
‫كما هو الحال عندما نستخدم متغريًا غري مهيأ ‪ ،‬فإن خطأ كهذا من غري املحتمل أن يكتشفه املرتجم‪.‬‬ ‫•‬
‫نتيجة الوصول إلى مؤرش غري صالح سلوك غري معرف‪.‬‬ ‫•‬
‫صالحا أم ال‪.‬‬
‫ً‬ ‫دائما ما إذا كان املؤرش املعني‬
‫ً‬ ‫لذلك ‪ ،‬يجب أن نعرف‬ ‫•‬

‫وبالرغم من أن املؤرشات في الحالتني ‪ 2‬و ‪ 3‬صالحة ‪،‬‬


‫إال أن هناك حدو ًدا ملا يمكننا فعله بهذه املؤرشات‪.‬‬ ‫•‬
‫وألن تلك املؤرشات ال تشري ألي كائن ‪ ،‬فال يسمح باستخدامها للوصول لكائن (مفرتض) تشري إليه‪.‬‬ ‫•‬
‫معرف‪.‬‬
‫فإذا ما حاولنا الوصول إلى كائن من خالل تلك املؤرشات ‪ ،‬فسيكون السلوك غري ّ‬ ‫•‬

‫استخدام مؤرش للوصول إلى كائن‬


‫‪Using a Pointer to Access an Object‬‬

‫عندما يشري مؤرش لكائن ‪ ،‬يمكننا استخدام عامل إلغاء املرجع ‪ ،‬الذي يُشار إليه بعالمة (النجمة *) للوصول لهذا‬
‫الكائن ‪:‬‬

‫;‪int ival = 42‬‬


‫‪int *p‬‬ ‫;‪= &ival‬‬ ‫‪// p holds address of ival; p pointer to ival‬‬
‫;‪cout << *p‬‬ ‫‪// * yields object to which p points; prints 42‬‬

‫إلغاء املرجع عن مؤرش ينتج عنه قيمة الكائن الذي يشري إليه املؤرش‪.‬‬

‫يمكننا التعيني على هذا الكائن عن طريق التعيني لنتيجة إلغاء املرجع ‪:‬‬

‫;‪*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‬‬

‫فارغا قبل محاولة استخدامه‪.‬‬


‫ً‬ ‫ال يشري املؤرش الفارغ إلى أي كائن‪ .‬يمكن للكود التحقق مما إذا كان املؤرش‬

‫هنالك عدة طرق للحصول على مؤرش فارغ‪:‬‬

‫;‪int *p1 = nullptr‬‬ ‫;‪// equivalent to int *p1 = 0‬‬


‫;‪int *p2 = 0‬‬ ‫‪// directly initializes p2 from literal constant 0‬‬
‫‪// must #include cstdlib‬‬
‫;‪int *p3 = NULL‬‬ ‫;‪// equivalent to int *p3 = 0‬‬

‫الطريقة األكرث مبارشة هي تهيئة املؤرش على الحرفية ‪ ، nullptr‬واملقدمة بواسطة املعيار الجديد‪.‬‬ ‫•‬
‫الحرفية ‪ nullptr‬عبارة عن حرفية لها نوع خاص يمكن تحويلها إلى أي نوع مؤرش آخر‪.‬‬ ‫•‬
‫وكبديل ‪ ،‬يمكننا تهيئة مؤرش على الحرفية ‪ ، 0‬كما نفعل في التعريف ‪.p2‬‬ ‫•‬
‫يعرفه العنوان ‪ cstdlib‬بالقيمة (‪.)0‬‬
‫تستخدم الربامج األقدم أحيا ًنا متغري معالجاً أولياً يسمى ‪ّ ، NULL‬‬
‫• سنقوم بوصف املعالج اﻷولي بمزيد من التفصيل في الفقرة ‪. 2.6.3‬‬
‫ما هو مفيد أن تعرفه اآلن هو أن املعالج اﻷولي هو برنامج يتم تشغيله قبل املرتجم‪.‬‬ ‫•‬
‫جزءا من مساحة االسم ‪.std‬‬
‫ً‬ ‫تتم إدارة متغريات املعالج اﻷولي بواسطة املعالج اﻷولي نفسه ‪ ،‬وهي ليست‬ ‫•‬
‫ونتيجة لذلك ‪ ،‬نشري إليها مبارشة بدون ‪.std::prefix‬‬ ‫•‬

‫تلقائيا بقيمته‪.‬‬
‫ً‬ ‫عندما نستخدم متغري املعالج اﻷولي ‪ ،‬فإن املعالج األولي يستبدل املتغري‬
‫وبالتالي ‪ ،‬فإن تهيئة مؤرش على ‪ NULL‬تعادل تهيئته إلى ‪.0‬‬ ‫•‬
‫عموما استخدام ‪ NULL‬وتستخدم ‪ nullptr‬بدال ً منها‪.‬‬
‫ً‬ ‫يجب أن تتجنب برامج يس‪ ++‬الحديثة‬ ‫•‬
‫ومن غري الرشعي تعيني املؤرش على متغري عدد صحيح ‪ ،‬حىت لو صادفت قيمة املتغري صفر‪.‬‬ ‫•‬

‫‪Initialize all Pointers‬‬ ‫قم بتهيئة جميع املؤرشات‬ ‫نصيحة ‪:‬‬

‫شائعا ألخطاء وقت التشغيل‪.‬‬


‫ً‬ ‫مصدرا‬
‫ً‬ ‫تعد املؤرشات غري املهيأة‬ ‫•‬
‫وكما هو حال أي متغري آخر غري مهيأ ‪ ،‬فإن ما يحدث عندما نستخدم مؤرشًا غري مهيأ سلوك غري معرف‪.‬‬ ‫•‬
‫دائما إلى عطل في وقت التشغيل‪.‬‬
‫ً‬ ‫يؤدي استخدام مؤرش غري مهيأ‬ ‫•‬
‫صعبا بشكل مدهش‪.‬‬
‫ً‬ ‫ومع ذلك ‪ ،‬فإن تصحيح األخطاء الناتجة قد يكون‬ ‫•‬

‫تحت معظم املرتجمات ‪،‬‬


‫عندما نستخدم مؤرشًا غري مهيأ ‪ ،‬يتم استخدام البتات املوجودة في الذاكرة اليت يوجد بها املؤرش كعنوان‪.‬‬ ‫•‬
‫استخدام مؤرش غري مهيأ هو طلب للوصول إلى كائن مفرتض في ذلك املوقع املفرتض‪.‬‬ ‫•‬
‫ال توجد طريقة للتميزي بني عنوان صالح وآخر غري صالح من بتات تصادف وجودها في ذاكرة تم‬ ‫•‬
‫تعيني املؤرش عليها‪.‬‬

‫توصيتنا دوماً بتهيئة جميع املتغريات مهمة بشكل خاص للمؤرشات‪.‬‬


‫إذا أمكن ‪ ،‬ﻻ تقم بتعريف مؤرش إﻻ بعد تعريف كائن ينبغي أن يشري إليه‪.‬‬ ‫•‬
‫إذا لم يكن هناك كائن لربطه بمؤرش ‪ ،‬فقم بتهيئة املؤرش على ‪ 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 = &ival‬‬ ‫‪// value in pi changed; pi now points to ival‬‬

‫فإننا نقوم بتعيني قيمة جديدة لـ ‪ ، pi‬مما يغري العنوان الذي يحمله ‪.pi‬‬

‫من ناحية أخرى ‪ ،‬عندما نكتب‬

‫;‪*pi = 0‬‬ ‫‪// value in ival changed; pi unchanged‬‬

‫فإن ‪ *pi‬هي القيمة اليت تؤرش إليها‪ pi‬ستتغري‪.‬‬

‫عمليات املؤرش اﻷخرى‬


‫‪Other Pointer Operations‬‬

‫طاملا أن املؤرش له قيمة صالحة ‪ ،‬فيمكننا استخدامه في رشط‪.‬‬


‫فكما نستخدم قيمة حسابية في رشط ‪ ،‬إن كان املؤرش يساوي ‪ ، 0‬فتقييم الرشط خاطئ ‪، false‬‬ ‫•‬
‫أما إن تم تقييم أي املؤرش غري صفري فالرشط صحيح ‪: . true‬‬ ‫•‬

‫;‪int ival = 1024‬‬


‫;‪int *pi = 0‬‬ ‫‪// pi is a valid, null pointer‬‬
‫‪int *pi2 = &ival; // pi2 valid pointer that holds address of ival‬‬
‫)‪if (pi‬‬ ‫…‬ ‫‪// pi has value 0, so condition evaluates as false‬‬
‫‪// ...‬‬

‫)‪if (pi2‬‬ ‫…‬ ‫;‪// pi2 points to ival, so it is not 0‬‬


‫‪// condition evaluates as true‬‬
‫‪// ...‬‬

‫بالنظر إلى مؤرشين صالحني من نفس النوع ‪،‬‬


‫يمكننا مقارنتهما باستخدام عوامل التساوي (==) أو عدم التساوي (=!)‪.‬‬ ‫•‬
‫نتيجة هذه العوامل نوع منطقي‪.‬‬ ‫•‬
‫يعد املؤرشان متساويني إن كانا يحمالن نفس العنوان وغري متساويني في الحاالت األخرى‪.‬‬ ‫•‬
‫فارغا ‪،‬‬
‫ً‬ ‫يكون املؤرشان يحمالن نفس العنوان (أي متساويان) إن كان كالهما‬ ‫•‬
‫أو كانا يتعامالن مع نفس الكائن ‪ ،‬أو كان كالهما مؤرشين ملا بعد نفس الكائن‪.‬‬ ‫•‬
‫الحظ أنه من املمكن ملؤرش كائن ومؤرش ما بعد نهاية كائن مختلف أن يحمال نفس العنوان‪.‬‬ ‫•‬
‫ستقارن هذه املؤرشات على قدم املساواة‪.‬‬ ‫•‬

‫ألن هذه العمليات تستخدم قيمة املؤرش ‪،‬‬


‫صالحا‪.‬‬
‫ً‬ ‫يجب أن يكون املؤرش املستخدم في رشط أو في املقارنة مؤرشًا‬ ‫•‬
‫فاستخدام مؤرش غري صالح كرشط أو في املقارنة يفيض إلى سلوك غري معرف‪.‬‬ ‫•‬

‫ستغطي الفقرة ‪ 3.5.3‬عمليات املؤرش اإلضافية‪.‬‬

‫مؤرشات *‪void‬‬
‫‪void* Pointers‬‬

‫النوع *‪ void‬هو نوع مؤرش خاص يمكنه االحتفاظ بعنوان أي كائن‪.‬‬

‫ومثل أي مؤرش آخر ‪ ،‬يحمل املؤرش *‪ void‬عنوا ًنا ‪ ،‬إﻻ أن نوع الكائن في هذا العنوان غري معروف بعد ‪:‬‬

‫;‪double obj = 3.14, *pd = &obj‬‬


‫‪// ok: void* can hold the address value of any data pointer type‬‬
‫;‪void *pv = &obj‬‬ ‫‪// obj can be an object of any type‬‬
‫;‪pv = pd‬‬ ‫‪// pv can hold a pointer to any type‬‬

‫ال يوجد الكثري مما يمكن القيام به باستخدام مؤرش *‪: void‬‬
‫فيمكننا مقارنته بمؤرش آخر ‪ ،‬أو تمريره أو إعادته من دالة ‪ ،‬ويمكننا تعيينه على مؤرش *‪ void‬آخر‪.‬‬ ‫•‬
‫ال يمكننا استخدام *‪ void‬للعمل على كائن يعالجه – فنحن ال نعرف نوعه بعد ‪،‬‬ ‫•‬
‫فالنوع يحدد تلك العمليات اليت يمكننا إجراؤها على الكائن‪.‬‬ ‫•‬
‫بشكل عام ‪،‬‬
‫نستخدم مؤرش *‪ void‬للتعامل مع الذاكرة كذاكرة ‪ ،‬بدال ً من الوصول لكائن مخزن في تلك الذاكرة‪.‬‬ ‫•‬
‫سنغطي استخدام مؤرشات *‪ void‬بهذه الطريقة في الفقرة ‪. 19.1.1‬‬ ‫•‬
‫ستوضح فقرة ‪ 4.11.3‬كيف يمكننا اسرتداد عنوان مخزن في مؤرش *‪. void‬‬ ‫•‬

‫قسم التدريبات ‪2.3.2‬‬

‫التمرين ‪: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‬‬

‫‪ 2٫3٫3‬فهم إعالنات النوع املركب‬


‫‪2.3.3. Understanding Compound Type Declarations‬‬

‫كما رأينا ‪،‬‬


‫يتكون تعريف املتغري من نوع أسايس وقائمة من املعلنات‪.‬‬ ‫•‬
‫يمكن لكل معلن أن يربط متغريه بالنوع األسايس بشكل مختلف عن املعلنات اﻷخرى في نفس التعريف‪.‬‬ ‫•‬

‫وبالتالي ‪ ،‬قد يعرف تعريف واحد متغريات من أنواع مختلفة‪:‬‬

‫‪// i is an int; p is a pointer to int; r is a reference to int‬‬


‫;‪int i = 1024, *p = &i, &r = i‬‬

‫تحذير‬
‫جزءا من ُمع ِلن‪.‬‬
‫ً‬ ‫يرتبك العديد من املربمجني بشأن التفاعل بني النوع األسايس وتعديل النوع الذي قد يكون‬

‫تعريف متغريات متعددة‬


‫‪Defining Multiple Variables‬‬

‫من املفاهيم الخاطئة الشائعة‪:‬‬


‫االعتقاد بأن معدل النوع (* أو &) ينطبق على جميع املتغريات املعرفة في جملة واحدة‪.‬‬ ‫•‬

‫معدل النوع واالسم املعلن‪:‬‬


‫ينشأ جزء من املشكلة ألنه يمكننا وضع مسافة بيضاء بني ّ‬

‫;‪int* p‬‬ ‫‪// legal but might be misleading‬‬

‫نقول أن هذا التعريف قد يكون مضلاًل ‪،‬‬


‫• ألنه يشري إلى أن *‪ int‬هو نوع كل متغري تم اإلعالن عنه في تلك الجملة‪.‬‬
‫بالرغم مما يظهر ‪ ،‬فإن النوع األسايس لهذا اإلعالن عدد صحيح ‪ ، int‬وليس مؤرش عدد صحيح *‪. int‬‬ ‫•‬
‫فالعالمة * تعدل نوع ‪ .p‬وال تذكر شيًئ ا عن أي كائنات أخرى يمكن اإلعالن عنها في نفس الجملة ‪:‬‬ ‫•‬
‫;‪int* p1, p2‬‬ ‫‪// p1 pointer to int; p2 int‬‬

‫هناك نوعان من األنماط الشائعة املستخدمة لتعريف متغريات متعددة باستخدام املؤرش أو نوع املرجع‪.‬‬

‫املعرف‪:‬‬
‫ّ‬ ‫معدل النوع بجوار‬
‫األول يضع ّ‬

‫;‪int *p1, *p2‬‬ ‫‪// both p1 and p2 pointers to int‬‬

‫يؤكد هذا النمط على أن املتغري له نوع مركب مشار إليه‪.‬‬

‫يعرف متغريًا واح ًدا فقط لكل جملة‪:‬‬


‫معدل النوع مع النوع لكنه ّ‬
‫النمط الثاني يضع ّ‬

‫;‪int* p1‬‬ ‫‪// p1 pointer to int‬‬


‫;‪int* p2‬‬ ‫‪// p2 pointer to int‬‬

‫مركبا‪.‬‬
‫ً‬ ‫نوعا‬
‫يعرف ً‬
‫يؤكد هذا النمط على أن اإلعالن ّ‬

‫تلميح‬
‫ال توجد طريقة صحيحة لتعريف املؤرشات أو املراجع‪ .‬اليشء املهم هو اختيار نمط واستخدامه باستمرار‪.‬‬ ‫•‬
‫نستخدم في هذا الكتاب النمط األول ونضع * (أو &) مع اسم املتغري‪.‬‬ ‫•‬

‫مؤرشات ملؤرشات‬
‫‪Pointers to Pointers‬‬

‫بشكل عام ‪،‬‬


‫عدالت النوع اليت يمكن تطبيقها على ُمع ِلن‪.‬‬
‫ال توجد حدود لعدد ُم ِّ‬ ‫•‬
‫دائما‪.‬‬
‫ً‬ ‫عندما يكون هناك أكرث من معدل ‪ ،‬فإنها تتحد بطرق منطقية لكنها ليست واضحة‬ ‫•‬
‫كمثال ‪ ،‬فكر في املؤرش‪ .‬املؤرش عبارة عن كائن في الذاكرة ‪ ،‬لذلك هو مثل أي كائن له عنوان‪.‬‬ ‫•‬
‫بالتالي ‪ ،‬يمكننا تخزين عنوان املؤرش في مؤرش آخر‪.‬‬ ‫•‬
‫نشري إلى كل مستوى مؤرش بنجمته الخاصة *‪.‬‬ ‫•‬

‫ما يعين أننا نكتب ** من أجل مؤرش ملؤرش ‪ ،‬و *** من أجل مؤرش ملؤرش ملؤرش ‪ ،‬وهكذا دواليك ‪:‬‬

‫‪int ival‬‬ ‫;‪= 1024‬‬


‫‪int *pi‬‬ ‫;‪= &ival‬‬ ‫‪// pi points to int‬‬
‫;‪int **ppi = &pi‬‬ ‫‪// ppi points to pointer to int‬‬
‫هنا ‪ pi‬هو مؤرش إلى ‪ int‬و ‪ ppi‬هو مؤرش إلى مؤرش ‪ .int‬قد نمثل هذه الكائنات كالتالي ‪:‬‬

‫‪ppi‬‬ ‫‪pi‬‬ ‫‪ival‬‬


‫‪1024‬‬

‫وكما أن إلغاء مرجع عن مؤرش لعدد صحيح ينتج عنه عدد صحيح ‪،‬‬ ‫•‬
‫فإن إلغاء مرجع عن مؤرش ملؤرش سينتج عنه مؤرش‪.‬‬ ‫•‬

‫وللوصول إلى الكائن األسايس ‪ ،‬يجب علينا إلغاء املرجع عن املؤرش األصلي مرتني ‪:‬‬

‫"‪cout << "The value of ival\n‬‬


‫‪<< "direct value:‬‬ ‫‪" << ival‬‬ ‫"‪<< "\n‬‬
‫‪<< "indirect value:‬‬ ‫‪" << *pi‬‬ ‫"‪<< "\n‬‬
‫;‪<< "doubly indirect value: " << **ppi << endl‬‬

‫يقوم هذا الربنامج بطباعة قيمة ‪ ival‬بثالث طرق مختلفة‪:‬‬ ‫•‬


‫أوال ‪ ،‬الطريقة املبارشة ؛ ثم الطريقة غري املبارشة عرب مؤرش للعدد الصحيح في ‪ pi‬؛‬ ‫•‬
‫وأخريًا بإلغاء املرجع عن ‪ ppi‬مرتني للوصول إلى قيمة ‪ ival‬األساسية‪.‬‬ ‫•‬

‫مراجع ملؤرشات‬
‫‪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.3.3‬‬

‫تمرين ‪:2.25‬‬
‫حدد أنواع وقيم كل من املتغريات التالية‪.‬‬
‫‪(a) int* ip,‬‬ ‫;‪&r = ip‬‬
‫‪(b) int‬‬ ‫‪i,‬‬ ‫;‪*ip = 0‬‬
‫‪(c) int* ip,‬‬ ‫;‪ip2‬‬
‫‪ . 2٫4‬املقيـــــــــــد ثابــــــــــت‬
‫‪2.4. const Qualifier‬‬

‫نريد أحيا ًنا تعريف متغري ال يمكن تغيري قيمته املعروفة‪.‬‬


‫فعلى سبيل املثال ‪ ،‬قد نرغب في استخدام متغري ليشري لحجم مخزن مؤقت ‪.buffer size‬‬ ‫•‬
‫فاستخدام متغري من شأنه أن يسهل علينا تغيري الحجم إن قررنا أن الحجم األصلي لم يكن ما نحتاجه‪.‬‬ ‫•‬
‫لكن من ناحية أخرى ‪،‬‬ ‫•‬
‫أيض ا منع الكود من إعطاء قيمة جديدة بالخطأ ملتغري نستخدمه ليمثل حجم املخزن املؤقت‪.‬‬
‫نود ً‬ ‫•‬

‫يمكننا جعل املتغري غري قابل للتغيري عن طريق تعريف نوع املتغري كـ ثابت ‪: const‬‬

‫;‪const int bufSize = 512‬‬ ‫‪// input buffer size‬‬

‫يعرف ‪ bufSize‬كــثابت‪ .‬فأي محاولة للتعيني على ‪ bufSize‬تعترب خطأ ‪:‬‬

‫‪bufSize = 512; // error: attempt to write to const object‬‬

‫ونظرًا ألنه ال يمكننا تغيري قيمة كائن ثابت بعد إنشائه ‪ ،‬فيجب تهيئته‪.‬‬

‫املهيِـئ تعبريًا معق ًدا بشكل تعسفي‪:‬‬


‫وكالعادة ‪ ،‬قد يكون ّ‬

‫;)(‪const int i = get_size‬‬ ‫‪// ok: initialized at run time‬‬


‫;‪const int j = 42‬‬ ‫‪// ok: initialized at compile time‬‬
‫;‪const int k‬‬ ‫‪// error: k is uninitialized 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‬ثابتة‪.‬‬ ‫•‬
‫ال يؤدي نسخ كائن إلى تغيري ذلك الكائن‪.‬‬ ‫•‬
‫لكن بمجرد عمل النسخة ‪ ،‬ال يمكن للكائن الجديد الوصول إلى الكائن األصلي‪.‬‬ ‫•‬

‫افرتاضياً الكائنات الثابتة تعد محلية إلى ملف‬


‫‪By Default, const Objects Are Local to a File‬‬

‫عندما يتم تهيئة كائن ثابت على ثابت وقت الرتجمة ‪ ،‬مثل تعريفنا لـ ‪:bufSize‬‬

‫;‪const int bufSize = 512‬‬ ‫‪// input buffer size‬‬

‫يقوم املرتجم في العادة باستبدال استخدامات املتغري بقيمته املقابلة أثناء الرتجمة‪.‬‬
‫أي أن املرتجم سينئش كو ًدا باستخدام القيمة ‪ 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‬‬

‫في هذا الربنامج ‪ ،‬يقوم ‪ file_1.cc‬بتعريف ‪ bufSize‬وتهيئته‪.‬‬ ‫•‬


‫ونظرًا ألن ذلك اإلعالن يتضمن ُمهيًئ ا ‪ ،‬فهو (كالعادة) تعريف‪ .‬مع ذلك ‪،‬‬ ‫•‬
‫ونظرًا ألن ‪ bufSize‬يعترب ثابتا ‪ ،‬فيجب علينا تعريف ‪ extern‬ليُستخدم ‪ bufSize‬في ملفات أخرى‪.‬‬ ‫•‬
‫أيضا‪.‬‬
‫عرف ‪ً extern‬‬ ‫ﻻحظ أن اإلعالن في ‪ّ file_1.h‬‬ ‫•‬

‫محليا لهذا امللف وأن تعريفه سيحدث في مكان آخر‪.‬‬


‫ً‬ ‫في هذه الحالة ‪ ،‬يشري ‪ extern‬إلى أن ‪ bufSize‬ليس‬

‫ملحوظة‬
‫ملشاركة كائن ثابت بني ملفات متعددة ‪ ،‬يجب عليك تعريف املتغري على أنه خارجي ‪.extern‬‬

‫تمارين القسم ‪2.4‬‬

‫التمرين ‪: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‬‬

‫كحال أي كائن آخر ‪ ،‬يمكن ربط مرجع بكائن نوع ثابت‪.‬‬


‫للقيام بذلك ‪ ،‬نستخدم املرجع لثابت ‪ ،‬وهو مرجع يشري لنوع ثابت‪.‬‬ ‫•‬
‫وبخالف املرجع العادي ‪ ،‬ال يمكن استخدام املرجع لثابت لتغيري الكائن املرتبط باملرجع ‪:‬‬ ‫•‬

‫‪const int ci‬‬ ‫;‪= 1024‬‬


‫;‪const int &r1 = ci‬‬ ‫‪// ok: both reference & underlying object const‬‬
‫;‪r1 = 42‬‬ ‫‪// error: r1 reference to const‬‬
‫;‪int &r2 = ci‬‬ ‫‪// error: non const reference to const object‬‬

‫ونظرًا ألنه ال يمكننا التعيني مبارشة على ‪ ، ci‬يجب أال نتمكن أيضاً من استخدام مرجع لتغيري ‪.ci‬‬
‫لذلك ‪ ،‬فإن تهيئة ‪ r2‬خطأ‪ .‬إن كانت هذه التهيئة رشعية ‪ ،‬فيمكننا استخدام ‪ r2‬لتغيري قيمة الكائن األسايس‪.‬‬
‫املرجع الثابت هو مرجع لثابت‬ ‫مصطلحات‪:‬‬

‫• يميل مربمجو يس‪ ++‬إلى اختصار عبارة "مرجع لثابت ‪"reference to const‬‬
‫• لتصبح "مرجعاً ثابتاً ‪."const Reference‬‬
‫• هذا االختصار منطقي ‪ -‬إن كنت تتذكر أنه اختصار‪.‬‬

‫فمن الناحية الفنية ‪ ،‬ال يوجد ما يسمى باملراجع الثابتة‪.‬‬ ‫•‬


‫وذلك ﻷن املرجع ليس كائنًا ‪ ،‬لذلك ال يمكننا جعل املرجع نفسه ثاب ًتا‪ .‬في الواقع ‪،‬‬ ‫•‬
‫ونظرًا لعدم وجود طريقة لجعل مرجع يشري لكائن مختلف ‪ ،‬فإن املراجع بطريقة ما ثابتة‪.‬‬ ‫•‬
‫سواء كان مرجعاً يشري لنوع ثابت أو غري ثابت فهو يؤثر على ما يمكننا فعله بهذا املرجع ‪،‬‬ ‫•‬
‫وليس ما إذا كان بإمكاننا تغيري ارتباط املرجع نفسه‪.‬‬ ‫•‬

‫التهيئة واملرجع لثابت‬


‫‪Initialization and References to const‬‬

‫في الفقرة ‪ ، 1.3.2‬الحظنا أن هناك استثناءين لقاعدة‬


‫تنص على أن نوع املرجع يجب أن يتطابق مع نوع الكائن الذي يشري إليه‪.‬‬ ‫•‬
‫االستثناء األول هو أنه يمكننا تهيئة مرجع لثابت على أي تعبري يمكن تحويله لنوع املرجع‪.‬‬ ‫•‬

‫فعلى وجه الخصوص ‪ ،‬يمكننا ربط مرجع لـثابت لكائن غري ثابت‪ ،‬أو حرفي ‪ ،‬أو تعبري أكرث عمومية ‪:‬‬

‫;‪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‬‬

‫مرجعا لكائن نوع مختلف‪:‬‬


‫ً‬ ‫أسهل طريقة لفهم هذا االختالف في قواعد التهيئة هي بالتفكري فيما يحدث عندما نربط‬

‫‪double‬‬ ‫;‪dval = 3.14‬‬


‫‪const int &ri‬‬ ‫;‪= dval‬‬

‫هنا يشري ‪ ri‬إلى عدد صحيح‪.‬‬ ‫•‬


‫صحيحا‪.‬‬
‫ً‬ ‫ستكون العمليات على ‪ ri‬هي عمليات عدد صحيح ‪ ،‬لكن ‪ dval‬رقم عرشي مزدوج ‪ ،‬وليس عد ًدا‬ ‫•‬
‫للتأكد من أن الكائن املرتبط به ‪ ri‬عدد صحيح ‪ ،‬يقوم املرتجم بتحويل هذا الكود إلى يشء يشبه‬ ‫•‬

‫‪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‬ليس بالتأكيد ما يقصده املربمج ‪ ،‬فإن اللغة تجعل الربط غري رشعي‪.‬‬ ‫•‬

‫قد يشري مرجع لثابت لكائن غري ثابت‬


‫‪A Reference to const May Refer to an Object That Is Not const‬‬

‫من املهم أن ندرك أن املرجع للثابت يقيد فقط ما يمكننا القيام به من خالل ذلك املرجع‪.‬‬
‫إن ربط مرجع لـثابت إلى كائن ال يخرب شيًئ ا عن ما إذا كان الكائن األسايس نفسه ثاب ًتا‪.‬‬ ‫•‬

‫ونظرًا ألن الكائن األسايس قد يكون غري ثابت ‪ ،‬فقد يتم تغيريه بوسائل أخرى‪:‬‬

‫‪int i‬‬ ‫;‪= 42‬‬


‫;‪int &r1 = i‬‬ ‫‪// r1 bound to i‬‬
‫;‪const int &r2 = i‬‬ ‫‪// r2 also bound to i; but cannot be used to change i‬‬
‫;‪r1 = 0‬‬ ‫‪// r1 not const; i now 0‬‬
‫;‪r2 = 0‬‬ ‫‪// error: r2 reference to const‬‬

‫يُعد ربط ‪ r2‬بالـعدد الصحيح ‪( i‬الغري ثابت) رشعياً‪.‬‬ ‫•‬


‫إﻻ أنه ال يمكننا استخدام ‪ r2‬لتغيري ‪ .i‬مع ذلك ‪ ،‬قد تتغري القيمة في ‪.i‬‬ ‫•‬
‫يمكننا تغيري ‪ i‬بالتعيني مبارشة ‪ ،‬أو بالتعيني ملرجع آخر مرتبط بـ ‪ ، i‬مثل ‪.r1‬‬ ‫•‬

‫‪ 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 = &pi; // ok: cptr may point to double that is const‬‬
‫;‪*cptr = 42‬‬ ‫‪// error: cannot assign to *cptr‬‬

‫في الفقرة ‪ 2.3.2‬الحظنا أن هناك استثناءين لقاعدة تنص على‬


‫أنه يجب أن تتطابق أنواع املؤرش مع الكائن الذي يشري إليه‪.‬‬ ‫•‬
‫أول استثناء هو أنه يمكننا استخدام مؤرش لثابت ليشري لكائن غري ثابت ‪:‬‬ ‫•‬

‫;‪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‬‬

‫على عكس املراجع ‪ ،‬تعد املؤرشات كائنات‪.‬‬


‫بالتالي ‪ ،‬كحال أي كائن آخر ‪ ،‬يمكن أن يكون لدينا مؤرش يكون بذاته ثابتاً‪.‬‬ ‫•‬
‫وكأي كائن ثابت آخر ‪ ،‬يجب تهيئة املؤرش الثابت ‪ ،‬وبمجرد تهيئته ‪ ،‬ال يمكن تغيري قيمته (عنوان يحمله)‪.‬‬ ‫•‬
‫نشري إلى مؤرش ثابت بوضع ‪ const‬بعد *‪.‬‬ ‫•‬
‫يشري هذا املوضع إلى أن املؤرش ‪ -‬وليس النوع املشار إليه – هو الثابت ‪:‬‬ ‫•‬

‫‪int errNumb‬‬ ‫;‪= 0‬‬


‫‪int *const curErr‬‬ ‫‪= &errNumb; // curErr will always point to errNumb‬‬
‫‪const double pi‬‬ ‫;‪= 3.14159‬‬
‫‪const double *const pip = &pi; // pip const pointer to const object‬‬

‫كما رأينا في الفقرة ‪ ، 2.3.3‬فإن أسهل طريقة لفهم هذه اإلعالنات هي قراءتها من اليمني إلى اليسار‪.‬‬
‫في هذه الحالة ‪ ،‬يكون الرمز األقرب إلى ‪ curErr‬هو ‪ ، const‬ما يعين أن ‪ curErr‬بذاته ثابت‪.‬‬ ‫•‬
‫يتكون نوع ذلك الكائن من باقي املُعلن‪.‬‬ ‫•‬
‫الرمز التالي في املعلن هو * ‪ ،‬ما يعين أن ‪ curErr‬هو مؤرش ثابت‪.‬‬ ‫•‬
‫أخريًا ‪ ،‬يكمل نوع اﻹعالن األسايس نوع ‪ ، curErr‬مؤرش ثابت لكائن نوع عدد صحيح‪.‬‬ ‫•‬
‫وباملثل ‪ ،‬فإن ‪ pip‬عبارة عن مؤرش ثابت لكائن نوع مزدوج ثابت‪.‬‬ ‫•‬

‫حقيقة أن املؤرش هو نفسه ثابت ال يخرب شيًئ ا عما إذا كان بإمكاننا استخدام املؤرش لتغيري الكائن األسايس‪.‬‬
‫كليا على النوع الذي يشري إليه املؤرش‪.‬‬
‫تعتمد إمكانية تغيري هذا الكائن ً‬ ‫•‬
‫فعلى سبيل املثال ‪ pip ،‬هو مؤرش ثابت لثابت‪.‬‬ ‫•‬
‫فال يمكن تغيري قيمة كائن تتم معالجته بواسطة ‪ pip‬وال العنوان املخزن في ‪.pip‬‬ ‫•‬
‫من ناحية أخرى ‪ ،‬يتعامل ‪ curErr‬مع عدد صحيح‪.‬‬ ‫•‬

‫بإمكاننا استخدام ‪ curErr‬لتغيري قيمة ‪: errNumb‬‬

‫‪*pip = 2.72; // error: pip pointer to const‬‬


‫‪// if object to which curErr points (i.e., errNumb) is nonzero‬‬
‫{ )‪if (*curErr‬‬
‫;)(‪errorHandler‬‬
‫‪*curErr = 0; // ok: reset value of object to which curErr is bound‬‬
‫}‬

‫قسم التدريبات ‪2.4.2‬‬

‫التمرين ‪: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‬‬

‫‪ 2٫4٫3‬الثابت عالي املستوى‬


‫‪2.4.3. Top-Level const‬‬

‫كما رأينا ‪ ،‬املؤرش عبارة عن كائن يمكن أن يشري إلى كائن مختلف‪.‬‬
‫نتيجة لذلك ‪ ،‬يمكننا التحدث بشكل مستقل حول ما إذا كان مؤرش ثاب ًتا ‪،‬‬ ‫•‬
‫وما إذا كانت الكائنات اليت يمكن أن يشري إليها ثابتة‪.‬‬ ‫•‬
‫نستخدم املصطلح ثابت املستوى العالي لنشري إلى أن املؤرش نفسه ثابت‪.‬‬ ‫•‬
‫عندما يمكن أن يشري مؤرش إلى كائن ثابت ‪ ،‬فإننا نشري إلى أن الثابت منخفض املستوى‪.‬‬ ‫•‬

‫بشكل عام ‪ ،‬يشري ثابت املستوى العالي إلى أن الكائن نفسه ثابت‪.‬‬
‫يمكن أن يظهر الثابت عالي املستوى في كائن من أي نوع‪.‬‬ ‫•‬
‫على سبيل املثال ‪ ،‬أحد األنواع الحسابية املدمجة أو نوع فئة أو نوع مؤرش‪.‬‬ ‫•‬
‫بينما يظهر الثابت منخفض املستوى في النوع األسايس لألنواع املركبة مثل املؤرشات أو املراجع‪.‬‬ ‫•‬

‫الحظ أن أنواع املؤرش ‪ ،‬على عكس معظم األنواع األخرى ‪،‬‬


‫يمكن أن يكون لها ثابت عالي املستوى ومنخفض املستوى بشكل مستقل ‪:‬‬ ‫•‬

‫;‪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‬‬
‫ال يؤدي نسخ كائن إلى تغيري الكائن املنسوخ‪.‬‬
‫ولذا ‪ ،‬من غري املهم ما إذا كان املنسوخ منه أو املنسوخ إليه ثاب ًتا‪.‬‬ ‫•‬

‫من ناحية أخرى ‪ ،‬ال يتم تجاهل ثابت املستوى املنخفض أب ًدا‪.‬‬ ‫•‬
‫فعندما نقوم بنسخ كائن ‪ ،‬يجب أن يكون لكال الكائنني نفس مقيد الثابت منخفض املستوى ‪،‬‬ ‫•‬
‫أو يجب أن يكون هناك تحويل بني نوعي الكائنني‪.‬‬ ‫•‬

‫بشكل عام ‪ ،‬يمكننا تحويل غري الثابت إلى ثابت لكن ليس العكس‪:‬‬

‫‪int *p = p3; // error: p3 has a low-level const but p doesn't‬‬


‫;‪p2 = p3‬‬ ‫‪// ok: p2 has the same low-level const qualification as p3‬‬
‫;‪p2 = &i‬‬ ‫*‪// ok: we can convert int* to const int‬‬
‫‪int &r = ci; // error: can't bind an ordinary int& to a const int object‬‬
‫‪const int &r2 = i; // ok: can bind const int& to plain int‬‬

‫يحتوي ‪ p3‬على كل من القيمة الثابتة ذات املستوى األعلى واملستوى املنخفض‪.‬‬


‫عندما ننسخ ‪ ، p3‬يمكننا تجاهل ثبات مستواه العالي لكن ال يمكننا تجاهل حقيقة أنه يشري لثابت‪.‬‬ ‫•‬
‫بالتالي ‪ ،‬ال يمكننا استخدام ‪ p3‬لتهيئة ‪ ، p‬مما يشري إلى ‪ int‬عادي (غري‪-‬ثابت)‪.‬‬ ‫•‬
‫من ناحية أخرى ‪ ،‬يمكننا تعيني ‪ p3‬على ‪.p2‬‬ ‫•‬
‫فكال املؤرشين لهما نفس النوع (ثابت منخفض املستوى)‪.‬‬ ‫•‬
‫ال يهم حقيقة أن ‪ p3‬هو مؤرش ثابت (أي أنه يحتوي على قيمة ثابتة عالية املستوى)‪.‬‬ ‫•‬

‫قسم التدريبات ‪2.4.3‬‬

‫التمرين ‪:2.30‬‬
‫‪ -‬بالنسبة إلى كل من التعريفات التالية ‪،‬‬
‫‪ -‬حدد ما إذا كان الكائن الذي يتم اإلعالن به يحتوي على ثابت مستوى أعلى أم ثابت منخفض املستوى‪.‬‬

‫;‪const int v2 = 0‬‬ ‫;‪int v1 = v2‬‬


‫;‪int *p1 = &v1, &r1 = v1‬‬
‫;‪const int *p2 = &v2, *const p3 = &i, &r2 = v2‬‬

‫التمرين ‪:2.31‬‬
‫‪ -‬نظرًا لإلعالنات الواردة في التمرين السابق ‪،‬‬
‫‪ -‬حدد ما إذا كانت التعيينات التالية رشعية أم ال‪.‬‬
‫‪ -‬ارشح كيف يتم تطبيق ثابت املستوى األعلى أو املستوى املنخفض في كل حالة‪.‬‬
‫;‪r1 = v2‬‬
‫;‪p1 = p2‬‬ ‫;‪p2 = p1‬‬
‫;‪p1 = p3‬‬ ‫;‪p2 = p3‬‬

‫‪ 2٫4٫4‬التعبري‪-‬الثابت والتعبريات الثابتة‬


‫‪2.4.4. constexpr and Constant Expressions‬‬

‫التعبري الثابت هو تعبري ال يمكن أن تتغري قيمته ويمكن تقييمه في وقت الرتجمة‪.‬‬
‫أيضا تعبرياً ثابتاً‪.‬‬
‫يعد الحرفي تعبرياً ثابتاً‪ .‬كذلك يعد كائن ثابت تمت تهيئته من تعبري ثابت ً‬ ‫•‬
‫وكما سرنى ‪ ،‬هناك العديد من سياقات اللغة تتطلب تعبريات ثابتة‪.‬‬ ‫•‬

‫واملهيِـئات‪ .‬فمثال‪:‬‬
‫ّ‬ ‫يعتمد كون كائن (أو تعبري) ما تعبرياً ثابتاً على األنواع‬

‫;‪const int max_files = 20‬‬ ‫‪// max_files constant expression‬‬


‫‪const int limit = max_files + 1; // limit constant expression‬‬
‫;‪int staff_size = 27‬‬ ‫‪// staff_size not constant expression‬‬
‫;)(‪const int sz = get_size‬‬ ‫‪// sz not constant expression‬‬

‫بالرغم من أن ‪ staff_size‬تمت تهيئته من حرفية ‪،‬‬


‫إال أنه ليس تعبريًا ثاب ًتا ألنه عدد صحيح رصيح وليس عد ًدا صحيحاً ثاب ًتا‪.‬‬ ‫•‬
‫مهيِـئه ال يعرف إﻻ وقت التشغيل‪.‬‬
‫من ناحية أخرى ‪ ،‬وبالرغم من أن ‪ sz‬عبارة عن ثابت ‪ ،‬فإن قيمة ّ‬ ‫•‬
‫ومن ثم ‪ ،‬فإن ‪ sz‬ليس تعبريًا ثاب ًتا‪.‬‬ ‫•‬

‫متغريات التعبري الثابت‬


‫‪constexpr Variables‬‬

‫املهيِـئ هو تعبري ثابت‪.‬‬


‫في نظام كبري ‪ ،‬قد يكون من الصعب (على وجه اليقني) تحديد أن ّ‬
‫مهيِـئ نعتقد أنه تعبري ثابت‪ .‬مع ذلك ‪،‬‬
‫نعرف متغرياً ثابتاً باستخدام ّ‬
‫فقد ّ‬ ‫•‬
‫املهيِـئ لم يكن تعبريًا ثاب ًتا‪.‬‬
‫ّ‬ ‫عندما نستخدم هذا املتغري في سياق يتطلب تعبريًا ثاب ًتا ‪ ،‬فقد نكتشف أن‬ ‫•‬
‫بشكل عام ‪ ،‬يمكن فصل تعريف كائن واستخدامه في مثل هذا السياق على نطاق واسع‪.‬‬ ‫•‬

‫بموجب املعيار الجديد ‪،‬‬


‫يمكننا أن نطلب من املرتجم التحقق من أن املتغري تعبري ثابت بإعالن املتغري في إعالن تعبري‪-‬ثابت‪.‬‬ ‫•‬
‫فاملتغريات اليت تم تعريفها كتعبريات‪-‬ثابتة هي ضمناً ثابتة ويجب أن تتم تهيئتها بواسطة تعبريات ثابتة‪:‬‬ ‫•‬

‫;‪constexpr int mf = 20‬‬ ‫‪// 20 constant expression‬‬


‫;‪constexpr int limit = mf + 1‬‬ ‫‪// mf + 1 constant expression‬‬
‫;)(‪constexpr int sz = size‬‬ ‫‪// ok only if size constexpr function‬‬
‫بالرغم من أننا ال نستطيع استخدام دالة عادية كمهئي ملتغري تعبري‪-‬ثابت ‪،‬‬
‫فسرنى في الفقرة ‪ 6.5.2‬أن املعيار الجديد يتيح لنا تعريف دوال معينة كتعبري‪-‬ثابت‪.‬‬ ‫•‬
‫يجب أن تكون هذه الدوال بسيطة بما يكفي بحيث يمكن للمرتجم تقييمها وقت الرتجمة‪.‬‬ ‫•‬
‫مهيِـئ متغري لتعبري‪-‬ثابت‪.‬‬
‫يمكننا استخدام دوال تعبري‪-‬ثابت في ّ‬ ‫•‬

‫أفضل املمارسات‬
‫بشكل عام ‪ ،‬من الجيد استخدام ‪ constexpr‬للمتغريات اليت تنوي استخدامها كتعبريات ثابتة‪.‬‬

‫اﻷنواع الحرفية‬
‫‪Literal Types‬‬

‫نظرًا ألن التعبري الثابت هو تعبري يمكن تقييمه في وقت الرتجمة ‪،‬‬
‫• فهناك حدود لألنواع اليت يمكننا استخدامها في إعالن تعبري‪-‬ثابت‪.‬‬
‫تُعرف األنواع اليت يمكننا استخدامها في التعبري الثابت باسم "األنواع الحرفية"‬ ‫•‬
‫ألنها بسيطة بما يكفي للحصول على قيمة حرفية‪.‬‬ ‫•‬

‫أنواعا حرفية‪.‬‬
‫ً‬ ‫من بني األنواع اليت استخدمناها حىت اآلن ‪ ،‬تعد أنواع الحسابات واملراجع واملؤرشات‬
‫فئة عنرص املبيعات ومكتبة املدخالت واملخرجات وأنواع السالسل ليست أنواعا حرفية‪.‬‬ ‫•‬
‫ومن ثم ‪ ،‬ال يمكننا تعريف متغريات من هذه األنواع كتعبريات‪-‬ثابتة‪.‬‬ ‫•‬
‫أنواعا أخرى من األنواع الحرفية في ‪ 7.5.6‬و ‪.19.3‬‬
‫ً‬ ‫سرنى‬ ‫•‬

‫وبالرغم من أنه يمكننا تعريف املؤرشات واملراجع كتعبريات‪-‬ثابتة ‪،‬‬


‫إال أن الكائنات اليت نستخدمها لتهيئتها محدودة للغاية‪.‬‬ ‫•‬
‫يمكننا تهيئة مؤرش تعبري‪-‬ثابت على حرفي املؤرش ‪( nullptr‬أي تعبري ثابت) الصفر‪.‬‬ ‫•‬
‫أيضا أن نشري إلى (أو نربط) كائن يظل في عنوان ثابت‪.‬‬
‫يمكننا ً‬ ‫•‬

‫ألسباب سنغطيها في الفقرة ‪ ، 6.1.1‬ال يتم عاد ًة تخزين املتغريات املعرفة داخل دالة في عنوان ثابت‪.‬‬
‫ومن ثم ‪ ،‬ال يمكننا استخدام مؤرش تعبري‪-‬ثابت لإلشارة إلى مثل هذه املتغريات‪.‬‬ ‫•‬
‫من ناحية أخرى ‪ ،‬فإن عنوان الكائن املعرف خارج أي دالة هو تعبري ثابت ‪،‬‬ ‫•‬
‫وبالتالي يمكن استخدامه لتهيئة مؤرش تعبري‪-‬ثابت‪.‬‬ ‫•‬

‫سرنى في الفقرة ‪، 6.1.1‬‬


‫أن الدوال قد تعرف املتغريات املوجودة عرب استدعاءات تلك الدالة‪.‬‬ ‫•‬
‫أيضا عناوين ثابتة‪.‬‬
‫ومثل كائن معرف خارج أي دالة ‪ ،‬فإن هذه الكائنات املحلية الخاصة لها ً‬ ‫•‬
‫مرتبطا بـ ( وقد يعالج مؤرش تعبري‪-‬ثابت ) مثل هذه املتغريات‪.‬‬
‫ً‬ ‫لذلك ‪ ،‬قد يكون مرجع تعبري‪-‬ثابت‬ ‫•‬
‫املؤرشات والتعبري الثابت‬
‫‪Pointers and constexpr‬‬

‫نعرف مؤرشًا في إعالن تعبري ثابت ‪ ،‬فإن معرف التعبري‪-‬الثابت ينطبق على املؤرش ‪،‬‬
‫من املهم أن نفهم أنه عندما ّ‬
‫وليس النوع الذي يشري إليه ‪:‬‬

‫‪const int *p‬‬ ‫;‪= nullptr‬‬ ‫‪// p pointer to const int‬‬


‫;‪constexpr int *q = nullptr‬‬ ‫‪// q const pointer to int‬‬

‫بالرغم مما يظهر ‪،‬‬


‫تماما ؛ فـ ‪ p‬مؤرش لثابت ‪ ،‬بينما ‪ q‬مؤرش ثابت‪.‬‬
‫ً‬ ‫فإن أنواع ‪ p‬و ‪ q‬مختلفة‬ ‫•‬
‫يعرفها‪.‬‬
‫يرجع االختالف إلى حقيقة أن التعبري‪-‬الثابت يفرض قيمة ثابتة عالية املستوى على الكائنات اليت ّ‬ ‫•‬
‫ومثل أي مؤرش ثابت آخر ‪ ،‬قد يشري مؤرش تعبري‪-‬ثابت إلى نوع ثابت أو غري ثابت ‪:‬‬ ‫•‬

‫‪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.4.4‬‬

‫التمرين ‪:2.32‬‬
‫‪ -‬هل الكود التالي رشعي أم ال؟‬
‫‪ -‬إذا لم يكن كذلك ‪ ،‬كيف يمكنك جعله رشعيا؟‬
‫;‪int null = 0, *p = null‬‬
‫‪ . 2٫5‬التعــــــــــامل مــــــــــع اﻷنــــــــــواع‬

‫‪2.5. Dealing with Types‬‬

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

‫‪ 2٫5٫1‬أسماء النوع املستعارة‬


‫‪2.5.1. Type Aliases‬‬

‫اسم النوع املستعار ‪ alias‬هو اسم مرادف لنوع آخر‪.‬‬


‫يسمح لنا أسماء النوع املستعارة بتبسيط تعريفات األنواع املعقدة ‪،‬‬ ‫•‬
‫ما يجعل هذه األنواع أسهل في االستخدام‪.‬‬ ‫•‬
‫أيضا التأكيد على الغرض من استخدام النوع‪.‬‬
‫يتيح لنا أسماء النوع املستعارة ً‬ ‫•‬
‫يمكننا تعريف نوع اسم مستعار بإحدى طريقتني‪.‬‬ ‫•‬

‫تقليديا ‪ ،‬نستخدم تعريف‪-‬النوع ‪: typedef‬‬

‫;‪typedef double wages‬‬ ‫‪// wages is a synonym for double‬‬


‫‪typedef wages base, *p; // base‬‬ ‫*‪is a synonym for double, p for double‬‬

‫قد تظهر كلمة تعريف‪-‬النوع ‪ typedef‬األساسية كجزء من إعالن النوع األسايس‪.‬‬ ‫•‬
‫تعرف أسماء النوع املستعارة بدال ً من املتغريات‪.‬‬
‫اﻹعالنات اليت تتضمن تعريف‪-‬النوع ّ‬ ‫•‬
‫وكحال أي إعالن آخر ‪،‬‬ ‫•‬
‫يمكن للمعلنات تضمني ُم ِّ‬
‫عدالت نوع تعرف أنواعاً مركبة مبنية من تعريفات النوع األساسية‪.‬‬ ‫•‬

‫الطريقة الثانية لتعريف نوع االسم املستعار قُدمت باملعيار الجديد ‪ ،‬عرب إعالن االسم املستعار ‪:‬‬

‫;‪using SI = Sales_item‬‬ ‫‪// SI is a synonym for Sales_item‬‬

‫يبدأ تعريف االسم املستعار بكلمة ‪ using‬األساسية متبوعة باالسم املستعار ثم =‪.‬‬ ‫•‬
‫يعرف إعالن االسم املستعار االسم على الجهة اليرسى من = كاسم مستعار للنوع الظاهر على الجهة اليمىن‪.‬‬
‫ّ‬ ‫•‬
‫نوع االسم املستعار عبارة عن اسم نوع ويمكن أن يظهر في أي مكان يحتمل أن يظهر فيه اسم نوع‪:‬‬

‫;‪wages hourly, weekly‬‬ ‫;‪// same as double hourly, weekly‬‬


‫;‪SI item‬‬ ‫‪// same as Sales_item item‬‬

‫مؤرشات‪ ،‬ثابت وأسماء النوع املستعارة‬


‫‪Pointers, const, and Type Aliases‬‬

‫أنواعا مركبة وثابتة إلى نتائج مذهلة‪.‬‬


‫ً‬ ‫يمكن أن تؤدي اإلعالنات اليت تستخدم أسماء نوع مستعارة تمثل‬
‫فعلى سبيل املثال ‪ ،‬تستخدم التعريفات التالية النوع ‪ ، pstring‬وهو نوع اسم مستعار لـ *‪: char‬‬

‫;‪typedef char *pstring‬‬


‫;‪const pstring cstr = 0‬‬ ‫‪// cstr constant pointer to char‬‬
‫;‪const pstring *ps‬‬ ‫‪// ps pointer to constant pointer to char‬‬

‫النوع األسايس في هذه التعريفات هو ‪.const pstring‬‬ ‫•‬


‫وكالعادة ‪ ،‬يقوم الثابت الذي يظهر في النوع األسايس بتعديل النوع املحدد‪.‬‬ ‫•‬
‫فنوع ‪ pstring‬هو "مؤرش لـ ‪."char‬‬ ‫•‬
‫لذا ‪ ،‬فإن ‪ const pstring‬هو مؤرش ثابت لـ ‪ - char‬وليس مؤرشًا لـ ‪ char‬ثابت‪.‬‬ ‫•‬

‫قد يكون من املغري ‪ -‬وإن كان غري صحيح ‪ -‬تفسري إعالن يستخدم اسم نوع مستعار‬
‫وذلك باستبدال االسم املستعار بنوعه املقابل من ناحية املفاهيم ‪:‬‬ ‫•‬

‫‪const char *cstr = 0; // wrong interpretation of const pstring cstr‬‬

‫مع ذلك ‪ ،‬فإن ذلك التفسري خاطئ‪.‬‬ ‫•‬


‫فعندما نستخدم ‪ pstring‬في إعالن ‪ ،‬يكون نوع اإلعالن األسايس هو نوع املؤرش‪.‬‬ ‫•‬
‫وعندما نعيد كتابة اإلعالن باستخدام ‪ ، * char‬يكون النوع األسايس ‪ char‬و * جزء من املعلن‪.‬‬ ‫•‬
‫في هذه الحالة ‪ ،‬الثابت ‪ char‬هو النوع األسايس‪.‬‬ ‫•‬
‫تعلن إعادة الكتابة هذه ‪ cstr‬كمؤرش لـ ‪ char‬ثابت وليس كمؤرش ثابت لـ ‪.char‬‬ ‫•‬

‫‪ 2٫5٫2‬محدد النوع التلقائي ‪auto‬‬


‫‪2.5.2. The auto Type Specifier‬‬

‫ليس من الشائع الرغبة في تخزين قيمة تعبري في متغري‪.‬‬


‫فلإلعالن عن املتغري ‪ ،‬يجب أن نعرف نوع ذلك التعبري‪.‬‬ ‫•‬
‫برنامجا ‪ ،‬قد يكون من الصعب ج ًدا ‪ -‬وأحيا ًنا من املستحيل ‪ -‬تحديد نوع التعبري‪.‬‬
‫ً‬ ‫عندما نكتب‬ ‫•‬
‫بموجب املعيار الجديد ‪ ،‬يمكننا السماح للمرتجم بتحديد النوع لنا باستخدام محدد النوع التلقائي ‪.auto‬‬ ‫•‬
‫لكن على عكس محددات النوع ‪ ،‬مثل املزدوج ‪ - double‬ذلك االسم محدد نوع ‪-‬‬ ‫•‬
‫املهيِـئ‪.‬‬
‫حيث يخرب ‪ auto‬املرتجم باستنتاج النوع من ّ‬ ‫•‬

‫مهيِـئ ‪:‬‬
‫بشكل ضمين ‪ ،‬يجب على متغري يستخدم ‪ 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‬‬

‫اﻷنواع املركبة‪ ،‬الثابت والتلقائي‬


‫‪Compound Types, const, and auto‬‬

‫املهيِـئ‪.‬‬
‫النوع الذي يستنتجه املرتجم للنوع التلقائي ليس دوماً هو نفسه نوع ّ‬
‫فأحياناً ‪ ،‬يقوم املرتجم بتعديل النوع ليتوافق مع قواعد التهيئة العادية‪.‬‬ ‫•‬
‫مرجعا ‪ ،‬فإننا بالفعل نستخدم الكائن الذي يشري إليه املرجع‪.‬‬
‫ً‬ ‫أوال ً ‪ ،‬وكما رأينا ‪ ،‬عندما نستخدم‬ ‫•‬
‫املهيِـئ هو الكائن املقابل‪.‬‬
‫ّ‬ ‫كمهيِـئ ‪ ،‬فإن‬
‫ّ‬ ‫مرجعا‬
‫ً‬ ‫وعلى وجه الخصوص ‪ ،‬عندما نستخدم‬ ‫•‬

‫يستخدم املرتجم نوع هذا الكائن ﻻستنتاج نوع ‪: auto‬‬

‫‪int i‬‬ ‫;‪= 0, &r = i‬‬


‫;‪auto a = r‬‬ ‫)‪// a int (r alias for i, which has type int‬‬

‫ثانيا ‪ ،‬يتجاهل ‪ auto‬عاد ًة ثوابت املستوى العالي‪.‬‬


‫ً‬ ‫•‬
‫فالعادة في عمليات التهيئة ‪ ،‬أنه يتم االحتفاظ بثابت املستوى املنخفض ‪،‬‬ ‫•‬
‫املهيِـئ مؤرشًا لثابت‪:‬‬
‫ّ‬ ‫كما هو الحال عندما يكون‬

‫;‪const int ci = i, &cr = ci‬‬


‫;‪auto b = ci‬‬ ‫)‪//b int (top-level const in ci is dropped‬‬
‫;‪auto c = cr‬‬ ‫)‪//c int (cr alias for ci whose const top-level‬‬
‫;‪auto d = &i‬‬ ‫)*‪//d int*(& of int object is int‬‬
‫;‪auto e = &ci‬‬ ‫)‪//e const int*(& of const object is low-level const‬‬

‫إذا أردنا أن يكون للنوع املستنتج قيمة ثابتة عال املستوى ‪ ،‬يجب أن نقول ذلك بشكل رصيح ‪:‬‬

‫‪const auto f = ci; // deduced type of ci is int; f has type const int‬‬

‫مرجعا لنوع استنتاج ‪ .auto‬فال تزال قواعد التهيئة العادية سارية‪:‬‬


‫ً‬ ‫أيضا تحديد أننا نريد‬
‫يمكننا ً‬

‫;‪auto &g = ci‬‬ ‫‪// g const int& that bound to ci‬‬


‫;‪auto &h = 42‬‬ ‫‪// error: we can't bind plain reference to literal‬‬
‫;‪const auto &j = 42‬‬ ‫‪// ok: we can bind const reference to literal‬‬

‫املهيِـئ‪.‬‬
‫ّ‬ ‫مرجعا لنوع ُمستنتج تلقائياً ‪ ،‬ال يتم تجاهل ثوابت املستوى العالي في‬
‫ً‬ ‫عندما نطلب‬
‫مرجعا بمهيـئ‪.‬‬
‫ً‬ ‫كالعادة ‪ ،‬ال تكون الثوابت عالية املستوى عندما نربط‬ ‫•‬

‫عندما نحدد عدة متغريات في نفس الجملة ‪،‬‬


‫جزءا من نوع اإلعالن األسايس‪.‬‬
‫ً‬ ‫من املهم أن نتذكر أن املرجع أو املؤرش هو جزء من معلن معني وليس‬ ‫•‬

‫تلقائيا ‪:‬‬
‫ً‬ ‫أنواعا متسقة يتم استنتاجها‬
‫ً‬ ‫املهيِـئات‬
‫كالعادة ‪ ،‬يجب أن توفر ّ‬

‫;‪auto k = ci, &l = i‬‬ ‫&‪// k int; l is int‬‬


‫;‪auto &m = ci, *p = &ci‬‬ ‫‪// m const int&; p pointer to const int‬‬
‫‪// error: type deduced from i is int; type deduced from &ci is const int‬‬
‫;‪auto &n = i, *p2 = &ci‬‬

‫قسم التدريبات ‪2.5.2‬‬

‫التمرين ‪:2.33‬‬
‫‪ -‬باستخدام تعريفات املتغريات من هذا القسم ‪ ،‬حدد ما يحدث في كل من هذه التعيينات‪:‬‬

‫;‪a = 42‬‬ ‫;‪b = 42‬‬ ‫;‪c = 42‬‬


‫;‪d = 42‬‬ ‫;‪e = 42‬‬ ‫;‪g = 42‬‬
‫التمرين ‪:2.34‬‬
‫برنامجا يحتوي على املتغريات والتعيينات من التمرين السابق‪.‬‬
‫ً‬ ‫‪ -‬اكتب‬
‫‪ -‬اطبع املتغريات قبل وبعد التعيينات للتحقق مما إذا كانت تنبؤاتك في التمرين السابق صحيحة‪.‬‬
‫‪ -‬إذا لم يكن األمر كذلك ‪،‬‬
‫‪ -‬فقم بدراسة األمثلة حىت تتمكن من إقناع نفسك أنك تعرف ما الذي أدى بك إلى االستنتاج الخاطئ‪.‬‬

‫تمرين ‪:2.35‬‬
‫‪ -‬حدد األنواع املستخلصة في كل من التعريفات التالية‪.‬‬
‫برنامجا لرتى ما إذا كنت على صواب‪.‬‬
‫ً‬ ‫‪ -‬بمجرد معرفة األنواع ‪ ،‬اكتب‬
‫;‪const int i = 42‬‬
‫;‪auto j = i; const auto &k = i; auto *p = &i‬‬
‫;‪const auto j2 = i, &k2 = i‬‬

‫‪ 2٫5٫3‬محدد النوع نوع‪-‬معلن‬


‫‪2.5.3. The decltype Type Specifier‬‬

‫أحياناً نريد تعريف متغري بنوع يستنتجه املرتجم من تعبري ما لكننا ال نريد استخدام ذلك التعبري لتهيئة املتغري‪.‬‬
‫بالنسبة ملثل هذه الحاالت ‪ ،‬قدم املعيار الجديد محد ًدا من نوع ثان ‪ ،‬هو النوع‪-‬املعلن ‪، decltype‬‬ ‫•‬
‫والذي يعيد نوع معامله‪ .‬حيث يحلل املرتجم التعبري لتحديد نوعه لكنه ال يقيم التعبري ‪:‬‬ ‫•‬

‫‪decltype(f()) sum = x; // sum has whatever type f returns‬‬

‫هنا ‪ ،‬ال يستدعي املرتجم ‪ ، f‬لكنه يستخدم النوع الذي سيعيده مثل ذلك االستدعاء كنوع لـ ‪. sum‬‬ ‫•‬
‫أي أن املرتجم يعطي ‪ sum‬نفس النوع الذي سيعاد إذا استدعينا ‪.f‬‬ ‫•‬
‫تختلف طريقة تعامل النوع‪-‬املعلن ‪ decltype‬مع الثابت عالي املستوى واملراجع اختال ًفا طفي ًفا ‪،‬‬ ‫•‬
‫عن طريقة النوع التلقائي ‪.auto‬‬ ‫•‬
‫فعندما يكون التعبري الذي نطبق عليه النوع‪-‬املعلن متغريًا ‪،‬‬ ‫•‬
‫يعيد النوع‪-‬املعلن نوع ذلك املتغري ‪ ،‬بما في ذلك ثابت املستوى العالي واملراجع ‪:‬‬ ‫•‬

‫;‪const int ci = 0, &cj = ci‬‬


‫;‪decltype(ci) x = 0‬‬ ‫‪// x has type const int‬‬
‫;‪decltype(cj) y = x‬‬ ‫‪// y has type const int& and bound to x‬‬
‫;‪decltype(cj) z‬‬ ‫‪// error: z reference and must be initialized‬‬

‫وألن ‪ cj‬عبارة عن مرجع ‪ ،‬فإن)‪ decltype(cj‬نوع مرجعي‪ .‬ومثل أي مرجع آخر ‪ ،‬يجب تهيئة ‪.z‬‬
‫تجدر اإلشارة إلى ‪:‬‬
‫عرف كمرجع ﻻ يتم التعامل معه كمرادف لكائن يشري إليه‪.‬‬
‫أن النوع‪-‬املعلن هو السياق الوحيد حيث متغري يُ ّ‬

‫النوع‪-‬املعلن واملراجع‬
‫‪decltype and References‬‬

‫عندما نطبق النوع‪-‬املعلن على تعبري ليس متغريًا ‪ ،‬نحصل على النوع الذي ينتج عن ذلك التعبري‪.‬‬
‫مرجعيا‪.‬‬
‫ً‬ ‫نوعا‬
‫• كما سرنى في الفقرة ‪ ، 4.1.1‬ستنتج بعض تعبريات النوع‪-‬املعلن ً‬

‫مرجعيا لتعبريات تنتج كائنات يمكن أن تكون على الجانب األيرس من التعيني‪:‬‬
‫ً‬ ‫نوعا‬
‫بشكل عام ‪ ،‬يعيد النوع‪-‬املعلن ً‬

‫‪// decltype of expression can be reference type‬‬


‫;‪int i = 42, *p = &i, &r = i‬‬
‫‪decltype(r + 0) b; // ok: addition yields int; b (uninitialized) int‬‬
‫;‪decltype(*p) c‬‬ ‫‪// error: c int& and must be initialized‬‬

‫هنا ‪ r‬مرجع ‪ ،‬لذا فإن)‪ decltype(r‬نوع مرجعي‪.‬‬ ‫•‬


‫فإذا أردنا النوع الذي يشري إليه ‪ ، r‬فيمكننا استخدام ‪ r‬في تعبري ‪،‬‬ ‫•‬
‫مثل ‪ ، r + 0‬وهو تعبري ينتج عنه قيمة نوعها غري مرجعي‪.‬‬ ‫•‬

‫مرجعا له‪.‬‬
‫ً‬ ‫من ناحية أخرى ‪ ،‬فإن عامل إلغاء املرجع هو مثال للتعبري الذي يعيد النوع‪-‬املعلن‬ ‫•‬
‫كما رأينا ‪ ،‬عندما نلغي مرجعاً عن مؤرش ‪ ،‬نحصل على الكائن الذي يشري إليه املؤرش‪.‬‬ ‫•‬
‫عالوة على ذلك ‪ ،‬يمكننا تعيني ذلك الكائن‪.‬‬ ‫•‬
‫بالتالي ‪ ،‬فإن النوع املستنتج من )‪ decltype(*p‬هو عدد صحيح مرجعي وليس عدداً صحيحاً فحسب‪.‬‬ ‫•‬

‫هناك اختالف مهم آخر بني النوع‪-‬املعلن والتلقائي وهو‬


‫أن االستنتاج الذي يقوم به النوع‪-‬املعلن يعتمد على شكل تعبريه املعطى‪.‬‬ ‫•‬
‫ما يمكن أن يكون محري ًا هو أن تضمني اسم متغري بني قوسني يؤثر على النوع املعاد بواسطة النوع‪-‬املعلن‪.‬‬ ‫•‬
‫فعندما نطبق النوع‪-‬املعلن على متغري بدون أي أقواس ‪ ،‬نحصل على نوع هذا املتغري‪.‬‬ ‫•‬
‫إذا قمنا بلف اسم املتغري في مجموعة واحدة أو أكرث من األقواس ‪ ،‬فسيقوم املرتجم بتقييم املعامل كتعبري‪.‬‬ ‫•‬
‫فمتغري عبارة عن تعبري يمكن أن يكون جانباً أيرس من تعيني‪.‬‬ ‫•‬

‫نتيجة لذلك ‪ ،‬ينتج عن النوع‪-‬املعلن ملثل هذا التعبري مرجع ‪:‬‬

‫‪// decltype of parenthesized variable is always reference‬‬


‫;‪decltype((i)) d‬‬ ‫‪// error: d int& and must be initialized‬‬
‫)‪decltype(i‬‬ ‫;‪e‬‬ ‫‪// ok: e (uninitialized) int‬‬
‫تحذير‬
‫دائما نوع مرجعي ‪،‬‬
‫ً‬ ‫تذكر أن ‪(( decltype‬متغري)) (الحظ ‪ ،‬األقواس املزدوجة) هو‬
‫مرجعا‪.‬‬
‫ً‬ ‫لكن ‪( decltype‬متغري) هو نوع مرجعي فقط إن كان املتغري‬

‫قسم التدريبات ‪2.5.3‬‬

‫التمرين ‪: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‬‬

‫معا واسرتاتيجية استخدام لها‪.‬‬


‫على أبسط مستوى ‪ ،‬تعد هيكلة البيانات طريقة تجميع عنارص بيانات مرتبطة ً‬
‫فمثالً ‪ ،‬تجمع فئتنا عنرص املبيعات ‪:‬‬ ‫•‬
‫أرقام الردمك (‪ ، )ISBN‬وعدد نسخ الكتاب اليت تم بيعها ‪ ،‬واإليرادات املرتبطة بتلك املبيعات‪.‬‬ ‫•‬
‫كما توفر مجموعة من العمليات ‪:‬‬ ‫•‬
‫مثل الدالة ‪ isbn‬وعوامل املدخالت واملخرجات << >> والجمع ‪ +‬والتعيني املركب ‪.=+‬‬ ‫•‬

‫نعرف أنواع بياناتنا من خالل تعريف فئة‪.‬‬


‫في يس ‪ّ ، ++‬‬ ‫•‬
‫يتم تعريف أنواع مكتبة السلسلة ‪ ،‬وقناة املدخالت ‪ ،‬وقناة املخرجات كفئات ‪،‬‬ ‫•‬
‫مثل نوع عنرص املبيعات الذي استخدمناه في الفصل ‪.1‬‬ ‫•‬
‫دعم يس‪ ++‬للفئات واسع النطاق ‪ -‬في الواقع ‪،‬‬ ‫•‬
‫تم تخصيص الجزأين الثالث والرابع إلى حد كبري لوصف املزيات املتعلقة بالفئة‪.‬‬ ‫•‬
‫وبالرغم من أن فئة عنرص املبيعات بسيطة ج ًدا ‪،‬‬ ‫•‬
‫إال أننا لن نتمكن من تعريفها بالكامل حىت نتعلم كيفية كتابة عواملنا في الفصل ‪.14‬‬ ‫•‬

‫‪ 2٫6٫1‬تعريف نوع بيانات املبيعات‬


‫‪2.6.1. Defining the Sales_data Type‬‬

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

‫سنعرف فئتنا على النحو التالي ‪:‬‬

‫{ ‪struct Sales_data‬‬
‫;‪std::string bookNo‬‬
‫;‪unsigned units_sold = 0‬‬
‫;‪double revenue = 0.0‬‬
‫;}‬
‫تبدأ فئتنا بكلمة ‪ struct‬األساسية ‪ ،‬متبوع ًة باسم الفئة وبنيتها (قد تكون فارغ ًة)‪.‬‬ ‫•‬
‫بنية الفئة تحاط بأقواس معقوفة وتشكل نطا ًقا جدي ًدا‪.‬‬ ‫•‬
‫يجب أن تكون األسماء املعرفة داخل الفئة فريدة داخلها لكن يمكن إعادة استخدام األسماء املعرفة خارجها‪.‬‬ ‫•‬
‫يجب أن يتبع القوس املجعد املغلق الذي ينهي بنية الفئة فاصلة منقوطة‪.‬‬ ‫•‬
‫الفاصلة املنقوطة مطلوبة ألنه يمكننا من تعريف متغريات بعد بنية الفئة ‪:‬‬ ‫•‬

‫;‪struct Sales_data { /* ... */ } accum, trans, *salesptr‬‬


‫‪// equivalent, but better way to define these objects‬‬
‫;} ‪struct Sales_data { /* ... */‬‬
‫;‪Sales_data accum, trans, *salesptr‬‬

‫تشري الفاصلة املنقوطة إلى نهاية قائمة اإلعالنات (الفارغة عاد ًة)‪.‬‬ ‫•‬
‫في العادة ‪ ،‬من الجيد تعريف كائن كجزء من تعريف الفئة‪.‬‬ ‫•‬
‫يؤدي القيام بذلك إلى حجب الكود‬ ‫•‬
‫وذلك عن طريق دمج تعريفات كيانني مختلفني ‪ -‬الفئة واملتغري ‪ -‬في جملة واحدة‪.‬‬ ‫•‬

‫تحذير‬
‫من الخطأ الشائع بني املربمجني الجدد نسيان الفاصلة املنقوطة في نهاية تعريف الفئة‪.‬‬

‫أعضاء بيانات الفئة‬


‫‪Class Data Members‬‬

‫تعرف بنية الفئة أعضاء الفئة‪.‬‬


‫لدى فئتنا أعضاء بيانات فقط‪ .‬تعرف أعضاء البيانات للفئة محتويات كائنات هذا النوع من الفئة‪.‬‬ ‫•‬
‫كل كائن له نسخته الخاصة من أعضاء بيانات الفئة‪.‬‬ ‫•‬
‫فال يؤدي تعديل أعضاء البيانات لكائن واحد إلى تغيري البيانات في أي كائن بيانات مبيعات آخر‪.‬‬ ‫•‬

‫نعرف أعضاء البيانات بنفس الطريقة اليت نعرف بها املتغريات العادية ‪:‬‬
‫معرفات واحد أو أكرث‪.‬‬
‫متبوعا بقائمة من ّ‬
‫ً‬ ‫أساسيا‬
‫ً‬ ‫نوعا‬
‫نعرف ً‬ ‫•‬
‫تتكون فئتنا من ثالثة أعضاء بيانات ‪:‬‬ ‫•‬
‫عضو نوع سلسلة ‪ string‬يُسمى رقم‪-‬الكتاب ‪، bookNo‬‬ ‫•‬
‫وعضو عدد صحيح بال_إشارة يُسمى وحدات_مباعة ‪، unit_sold‬‬ ‫•‬
‫وعضو نوع مزدوج عرشي يسمى إيرادات ‪.revenue‬‬ ‫•‬
‫سيحتوي كل كائن بيانات مبيعات ‪ Sales_data‬على أعضاء البيانات الثالثة هذه‪.‬‬ ‫•‬

‫مهيِـئ داخل‪-‬الفئة لعضو البيانات‪.‬‬


‫بموجب املعيار الجديد ‪ ،‬يمكننا توفري ّ‬ ‫•‬
‫املهيِـئ داخل الفئة لتهيئة أعضاء البيانات‪.‬‬
‫عندما نقوم بإنشاء كائنات ‪ ،‬سيتم استخدام ّ‬ ‫•‬
‫افرتاضيا‪.‬‬
‫ً‬ ‫مهيِـئ لها‬
‫تتم تهيئة األعضاء اليت ال ّ‬ ‫•‬
‫وبالتالي ‪ ،‬عندما نعرف كائنات بيانات املبيعات ‪ ،‬سيتم تهيئة الوحدات املباعة واإليرادات على ‪، 0‬‬ ‫•‬
‫وسيتم تهيئة رقم‪-‬الكتاب على سلسلة فارغة‪.‬‬ ‫•‬

‫هيئات داخل الفئة بالصيغة اليت يمكننا استخدامها ‪:‬‬


‫يتم تقييد امل ُ ّ‬
‫يجب إما أن تكون متضمنة داخل أقواس معقوفة أو تلي عالمة =‪.‬‬ ‫•‬
‫قد ال يسمح لنا بتحديد ُمهئي داخل‪-‬الفئة داخل أقواس‪.‬‬ ‫•‬

‫في الفقرة ‪، 7.2‬‬


‫سرنى أن يس‪ ++‬تملك كلمة ثانية ‪ ، class ،‬يمكن استخدامها لتعريف هياكل بياناتنا الخاصة‪.‬‬ ‫•‬
‫سنرشح في هذا القسم سبب استخدامنا لـ ‪ struct‬هنا‪.‬‬ ‫•‬
‫ولكن إلى أن نغطي املزيات اإلضافية املتعلقة بالفئة في الفصل السابع ‪،‬‬ ‫•‬
‫فينبغي استخدام البنية ‪ struct‬لتعريف هياكل بياناتك الخاصة‪.‬‬ ‫•‬

‫تمارين القسم ‪2.6.1‬‬

‫التمرين ‪:2.39‬‬
‫‪ -‬قم برتجمة الربنامج التالي ملعرفة ما يحدث عندما تنىس الفاصلة املنقوطة بعد تعريف فئة‪.‬‬
‫‪ -‬تذكر الرسالة للرجوع إليها في املستقبل‪.‬‬

‫‪struct Foo { /*empty*/ } // Note: no semicolon‬‬


‫)(‪int main‬‬
‫{‬
‫;‪return 0‬‬
‫}‬
‫التمرين ‪:2.40‬‬
‫اكتب نسختك الخاصة من فئة بيانات املبيعات ‪.Sales_data‬‬

‫‪ 2٫6٫2‬استخدام فئة بيانات املبيعات‬


‫‪2.6.2. Using the Sales_data Class‬‬

‫على عكس فئة عنرص املبيعات ‪،‬‬


‫ال توفر فئتنا بيانات املبيعات أي عمليات‪.‬‬ ‫•‬
‫حيث يتعني على مستخدميها كتابة العمليات اليت يحتاجون إليها‪.‬‬ ‫•‬

‫فعلى سبيل املثال ‪ ،‬سنكتب نسخة من الربنامج من الفقرة ‪ 1٫5٫2‬واليت طبعت مجموع معاملتني‪.‬‬
‫ستكون املدخالت في برنامجنا عبارة عن معامالت مثل‬ ‫•‬
‫‪0-201-78345-X 3 20.00.0000‬‬
‫‪0-201-78345-X 2 25.00.0000‬‬

‫كل معاملة ستحمل رقم الردمك ‪ ،‬وعدد الكتب املباعة ‪ ،‬والسعر الذي تم بيع كل كتاب به‪.‬‬

‫إضافة كائين بيانات مبيعات‬


‫‪Adding Two Sales_data Objects‬‬

‫نظرًا ألن بيانات املبيعات ال توفر أي عمليات ‪،‬‬


‫• فسيتعني علينا كتابة أكوادنا الخاصة للقيام بعمليات املدخالت واملخرجات واإلضافة‪.‬‬
‫سنفرتض أن فئتنا معرفة داخل ‪.Sales_data.h‬‬ ‫•‬
‫سرنى كيفية تعريف هذا العنوان في ‪. 2.6.3‬‬ ‫•‬
‫ونظرًا ألن هذا الربنامج سيكون أطول من أي برنامج كتبناه حىت اآلن ‪ ،‬فسنرشحه في أجزاء منفصلة‪.‬‬ ‫•‬

‫بشكل عام ‪ ،‬سيكون لربنامجنا الهيكل التالي‪:‬‬

‫>‪#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‬‬ ‫•‬
‫نحتاج إلى هذا العنوان ألن كودنا سيتعني عليه إدارة عضو رقم‪-‬الكتاب ‪ ،‬والذي نوعه سلسلة‪.‬‬ ‫•‬

‫قراءة بيانات إلى كائن بيانات املبيعات‬


‫‪Reading Data into a Sales_data Object‬‬

‫بالرغم من أننا لن نصف نوع مكتبة السلسلة بالتفصيل حىت الفصلني ‪ 3‬و ‪، 10‬‬
‫إال أننا نحتاج إلى معرفة القليل فقط عنها من أجل تعريف واستخدام العضو ‪.ISBN‬‬ ‫•‬
‫نوع السلسلة يحمل سلسلة من األحرف‪.‬‬ ‫•‬
، == ‫تتضمن عملياتها عوامل مدخالت ومخرجات << >> وتساوي‬ •
.‫ على التوالي‬، ‫وذلك لقراءة السالسل وكتابتها ومقارنتها‬ •

: ‫بهذه املعرفة يمكننا كتابة كود لقراءة أول معاملة‬

double price = 0; // price per book, used to calculate total revenue


// read first transactions: ISBN, number of books sold, price per book
std::cin >> data1.bookNo >> data1.units_sold >> price;
// calculate total revenue from price and units_sold
data1.revenue = data1.units_sold * price;

.‫تحتوي معامالتنا على السعر الذي تم بيع كل كتاب به لكن هيكل بياناتنا يخزن إجمالي اإليرادات‬
: ‫ جملة املدخالت‬.revenue ‫ والذي سنحسب منه عضو اإليرادات‬، price ‫سنقرأ بيانات املعاملة إلى املزدوج‬

std::cin >> data1.bookNo >> data1.units_sold >> price;

.data1 ‫ للكائن‬units_sold ‫ و‬bookNo ‫تستخدم عامل النقطة للقراءة إلى أعضاء‬ •


price ‫ و‬data1.units_sold ‫تعني الجملة األخرية منتج‬ •
.data1 ‫ في‬revenue ‫على عضو اإليرادات‬ •

:data2 ‫سيقوم برنامجنا بعد ذلك بتكرار نفس الكود لقراءة البيانات إلى‬

// read the second transaction


std::cin >> data2.bookNo >> data2.units_sold >> price;
data2.revenue = data2.units_sold * price;

‫طباعة مجموع كائين بيانات املبيعات‬


Printing the Sum of Two Sales_data Objects

:‫ وإال فسنطبع رسالة خطأ‬، ‫مهمتنا األخرى هي التحقق من أن املعامالت هي لنفس رقم الردمك‬

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.6.2‬‬

‫التمرين ‪:2.41‬‬
‫‪ -‬استخدم فئة ‪ Sales_data‬إلعادة كتابة التدريبات الواردة في ‪ ، 1.5.1‬و ‪ ، 1.5.2‬و ‪1.6‬‬
‫‪ -‬في الوقت الحالي ‪ ،‬يجب عليك تعريف فئتك ‪ Sales_data‬في نفس امللف مثل دالتك ‪. main‬‬

‫‪ 2٫6٫3‬كتابة ملفات عنواننا‬


‫‪2.6.3. Writing Our Own Header Files‬‬

‫بالرغم من أننا سرنى في الفقرة ‪ ، 19.7‬كيف يمكننا تعريف فئة داخل دالة ‪ ،‬فإن هذه الفئات لها دوال محدودة‪.‬‬
‫نتيجة لذلك ‪ ،‬ال يتم تعريف الفئات عاد ًة داخل الدوال‪.‬‬ ‫•‬
‫عندما نعرف فئة خارج دالة ‪ ،‬قد يكون هناك تعريف واحد فقط لتلك الفئة في أي ملف مصدر معني‪.‬‬ ‫•‬
‫إضافة إلى ذلك ‪ ،‬إذا استخدمنا فئة في عدة ملفات مختلفة ‪،‬‬ ‫•‬
‫فيجب أن يكون تعريف الفئة هي نفسها في كل ملف‪.‬‬ ‫•‬

‫للتأكد من أن تعريف الفئة هو نفسه في كل ملف ‪،‬‬


‫يتم تعريف الفئات عاد ًة في ملفات العنوان ‪.header files‬‬ ‫•‬
‫عاد ًة ما يتم تخزين الفئات في عناوين يُشتق اسمها من اسم الفئة‪.‬‬ ‫•‬
‫فعلى سبيل املثال ‪ ،‬يتم تعريف نوع مكتبة السلسلة ‪ string‬في عنوان السلسلة ‪.string‬‬ ‫•‬
‫وباملثل ‪ ،‬كما رأينا بالفعل ‪،‬‬ ‫•‬
‫سنعرف فئة بيانات املبيعات ‪ Sales_data‬في ملف عنوان يسمى ‪.Sales_data.h‬‬ ‫•‬

‫تحتوي العناوين (عاد ًة ) على كيانات (مثل تعريفات فئات ومتغريات لثوابت ولتعبريات ثابتة) ‪،‬‬ ‫•‬
‫يمكن تعريفها مرة واحدة فقط في أي ملف معني‪ .‬مع ذلك ‪،‬‬ ‫•‬
‫غالبا ما تحتاج العناوين إلى استخدام أقسام من عناوين أخرى‪.‬‬
‫ً‬ ‫•‬
‫مثالً ‪ ،‬نظرًا ألن فئتنا بيانات املبيعات بها عضو سلسلة ‪،‬‬ ‫•‬
‫يجب أن يقوم العنوان ‪ Sales_data.h‬بتضمني عنوان السلسلة‪.‬‬ ‫•‬
‫أيضا إلى تضمني عنوان السلسلة‪،‬‬
‫كما رأينا ‪ ،‬تحتاج الربامج اليت تستخدم بيانات املبيعات ً‬ ‫•‬
‫وذلك من أجل استخدام عضو رقم الكتاب‪.‬‬ ‫•‬
‫نتيجة لذلك ‪ ،‬ستتضمن الربامج اليت تستخدم بيانات املبيعات عنوان السلسلة مرتني ‪:‬‬ ‫•‬
‫مرة مبارشة ومرة كأثر جانيب لتضمني ‪.Sales_data.h‬‬ ‫•‬
‫ونظرًا ألنه قد يتم تضمني العنوان أكرث من مرة ‪،‬‬ ‫•‬
‫سنحتاج إلى كتابة عناويننا بطرق آمنة حىت لو تم تضمني العنوان عدة مرات‪.‬‬ ‫•‬

‫ملحوظة‬
‫عندما يتم تحديث عنوان ‪ ،‬يجب إعادة تجميع امللفات املصدر اليت تستخدم ذلك العنوان‬
‫ﻷخذ اإلعالنات الجديدة أو املتغرية‪.‬‬

‫مقدمة موجزة عن املعالج اﻷولي‬


‫‪A Brief Introduction to the Preprocessor‬‬

‫شيوعا لجعل تضمني عنوان ما عدة مرات آمنًا يعتمد على املعالج اﻷولي‪. PreProcessor‬‬
‫ً‬ ‫األسلوب األكرث‬
‫املعالج اﻷولي ‪ -‬والذي ورثته يس‪ ++‬من يس ‪ -‬برنامج يعمل قبل املرتجم ويغري النص املصدر لربامجنا‪.‬‬ ‫•‬
‫تعتمد برامجنا بالفعل على أحد أقسام املعالج اﻷولي‪. #include :‬‬ ‫•‬
‫فعندما يرى ‪ ، #include‬فإنه يستبدلها بمحتويات العنوان املحدد‪.‬‬ ‫•‬

‫حراس العنوان ‪.Header guards‬‬


‫أيضا املعالج اﻷولي لتعريف ّ‬
‫تستخدم برامج يس‪ً ++‬‬
‫تعتمد حراسة العنوان على متغريات ما قبل املعالجة‪.‬‬ ‫•‬
‫متغريات املعالج اﻷولي لها حالة من حالتني محتملتني‪:‬‬ ‫•‬
‫إما أن تكون معرفة أو غري معرفة‪.‬‬ ‫•‬
‫اسما ويحدد هذا االسم كمتغري معالج أولي‪.‬‬
‫ً‬ ‫يأخذ التوجيه ‪#define‬‬ ‫•‬
‫هناك توجيهان آخران يختربان ما إذا كان متغري ما قبل املعالج قد تم تعريفه أم ال‪:‬‬ ‫•‬
‫صحيحا إذا تم تعريف املتغري ‪،‬‬
‫ً‬ ‫‪ #ifdef‬يكون‬ ‫•‬
‫صحيحا إذا لم يتم تعريف املتغري‪.‬‬
‫ً‬ ‫‪ #ifndef‬يكون‬ ‫•‬
‫صحيحا ‪ ،‬فسيتم معالجة كل ما يلي ‪ #ifdef‬أو ‪ #ifndef‬حىت ‪ #endif‬املطابق‪.‬‬
‫ً‬ ‫فإن كان االختبار‬ ‫•‬

‫يمكننا استخدام هذه اﻷقسام للحماية من التضمني املتعدد على النحو التالي‪:‬‬

‫‪#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‬‬ ‫•‬

‫تحذير‬
‫ال تحرتم أسماء متغريات املعالج اﻷولي قواعد تحديد النطاق لـ يس‪.++‬‬

‫يجب أن تكون متغريات املعالج اﻷولي ‪،‬‬ ‫•‬


‫بما في ذلك أسماء حراسة العنوان ‪ ،‬فريدة من نوعها في جميع أنحاء الربنامج‪.‬‬ ‫•‬
‫عاد ًة ما نضمن التفرد من خالل تأسيس اسم الحارس على اسم فئة في العنوان‪.‬‬ ‫•‬
‫ولتجنب تضارب األسماء مع الكيانات األخرى في برامجنا ‪،‬‬ ‫•‬
‫عاد ًة ما يتم كتابة متغريات املعالج اﻷولي بأحرف كبرية‪.‬‬ ‫•‬

‫أفضل املمارسات‬
‫ينبغي أن تحتوي العناوين على حراسة ‪ ،‬حىت لو لم يتم تضمينها (بعد) في عنوان آخر‪.‬‬ ‫•‬
‫تافها ‪ ،‬ومن خالل تعريفها بشكل اعتيادي ‪،‬‬
‫ً‬ ‫تعترب كتابة حارسات العناوين أمرًا‬ ‫•‬
‫فلن تحتاج إلى تحديد ما إذا كانت هناك حاجة إليها أم ال‪.‬‬ ‫•‬

‫قسم التمارين ‪2.6.3‬‬


‫التمرين ‪:2.42‬‬
‫‪ -‬اكتب إصدارك الخاص من عنوان ‪Sales_data.h‬‬
‫‪ -‬واستخدمه إلعادة كتابة التمرين من الفقرة ‪. 2.6.2‬‬
‫مــلـــخــــــــــص الــفــــصــــــــــــل‬

‫‪Chapter‬‬ ‫‪Summary‬‬

‫تعد األنواع أساسية لجميع أعمال الربمجة في يس‪.++‬‬

‫يعرف كل نوع متطلبات التخزين والعمليات اليت يمكن إجراؤها على كائنات ذلك النوع‪.‬‬
‫توفر اللغة مجموعة من األنواع األساسية املدمجة مثل العدد الصحيح ‪ int‬والحرف ‪، char‬‬ ‫•‬
‫ارتباطا وثي ًقا بتمثيلها على أجهزة الجهاز‪.‬‬
‫ً‬ ‫واليت ترتبط‬ ‫•‬

‫يمكن أن تكون األنواع غري‪-‬ثابتة أو ثابتة ؛‬


‫يجب تهيئة أي كائن ثابت ‪ ،‬وبمجرد التهيئة ‪ ،‬ال يمكن تغيري قيمته‪.‬‬ ‫•‬
‫إضافة إلى ذلك ‪ ،‬يمكننا تعريف أنواع مركبة ‪ ،‬مثل املؤرشات أو املراجع‪.‬‬ ‫•‬
‫النوع املركب عبارة عن نوع يتم تعريفه بمصطلحات نوع آخر‪.‬‬ ‫•‬

‫تتيح لنا اللغة تعريف أنواعنا الخاصة من خالل تعريف فئات‪.‬‬


‫تستخدم املكتبة قسم الفئة لتوفري مجموعة من التجريدات عالية املستوى ‪،‬‬ ‫•‬
‫مثل املدخالت واملخرجات وأنواع السلسلة‪.‬‬ ‫•‬
‫مـــصــطــلـــحــــــــــات مــــعــــــــــرفـــــــــة‬

‫‪Defined‬‬ ‫‪Terms‬‬

‫‪address‬‬ ‫عنوان‪ :‬رقم يمكن من خالله العثور على بايت في الذاكرة‪.‬‬

‫يعرف مراد ًفا لنوع آخر‪:‬‬


‫إعالن اسم مستعار ‪ّ :‬‬
‫‪alias declaration‬‬ ‫‪using name = type‬‬
‫يعلن ‪ name‬كمرادف للنوع ‪.type‬‬

‫أنواع حسابية أنواع مدمجة تمثل القيم املنطقية واألحرف واألعداد الصحيحة وأرقام‬
‫‪arithmetic types‬‬
‫النقطة العائمة العرشية‪.‬‬

‫مصفوفة ‪ :‬بنية بيانات تحتوي على مجموعة من الكائنات غري املسماة اليت يتم‬
‫‪array‬‬
‫الوصول إليها بواسطة فهرس‪ .‬يغطي الفصل ‪ 5‬املصفوفات بالتفصيل‪.‬‬

‫‪auto‬‬ ‫مهيِـئه‪.‬‬
‫محدد نوع تلقائي يستنتج نوع املتغري من ّ‬

‫نوع أسايس ‪ :‬محدد نوع ربما مقيد بواسطة ثابت ‪ ،‬يسبق املعلنات في إعالن‪.‬‬
‫‪base type‬‬
‫يوفر النوع األسايس النوع الشائع الذي يمكن للمعلنات البناء عليه في إعالن‪.‬‬

‫إقران ‪ :‬إقران اسم بكيان معني بحيث تكون استخدامات االسم استخدامات للكيان‬
‫‪bind‬‬
‫األسايس‪ .‬مثال يعد املرجع اسماً مقرتن بكائن‪.‬‬

‫‪byte‬‬ ‫بايت ‪ :‬أصغر وحدة ذاكرة قابلة للعنونة‪ .‬في معظم األجهزة ‪ ،‬يكون البايت ‪ 8‬بت‪.‬‬

‫‪class member‬‬ ‫عضو فئة ‪ :‬جزء من فئة‬

‫‪compound type‬‬ ‫نوع مركب ‪ :‬نوع معرف برشوط ومصطلحات نوع آخر‪.‬‬
‫ثابت ‪ :‬مقيد نوع يُستخدم لتعريف كائنات ال يمكن تغيري قيمتها‪ .‬يجب تهيئة أي كائن‬
‫‪const‬‬
‫ثابت ‪ ،‬ألنه ال توجد طريقة ملنحها قيمة بعد تعريفها‪.‬‬

‫‪const pointer‬‬ ‫مؤرش ثابت ‪ :‬عبارة عن مؤرش يكون ثابتاً‪.‬‬

‫‪const reference‬‬ ‫مرجع ثابت ‪ :‬مرادف ملرجع يكون ثابتاً‪.‬‬

‫‪constant expression‬‬ ‫تعبري ثابت ‪ :‬تعبري يمكن تقييمه في وقت الرتجمة‪.‬‬

‫‪constexpr‬‬ ‫تعبري‪-‬ثابت ‪ :‬متغري يمثل تعبريًا ثاب ًتا‪ .‬يشمل دوال تعبري‪-‬ثابت‪.‬‬

‫تحويل ‪ :‬عملية يتم فيها تحويل قيمة نوع لقيمة نوع آخر‪ .‬تعرف اللغة تحويالت بني‬
‫‪conversion‬‬
‫األنواع املدمجة‪.‬‬

‫عضو بيانات ‪ :‬عنارص بيانات تشكل كائنًا‪ .‬كل كائن فئة معينة له نسخته الخاصة من‬
‫‪data member‬‬
‫أعضاء بيانات الفئة‪ .‬يمكن تهيئة أعضاء البيانات عند اإلعالن عنها داخل الفئة‪.‬‬

‫إعالن ‪ :‬توكيد لوجود متغري أو دالة أو نوع معرف في مكان آخر‪ .‬ال يجوز استخدام‬
‫‪declaration‬‬
‫األسماء حىت يتم تعريفها أو اإلعالن عنها‪.‬‬

‫‪declarator‬‬ ‫وم ِّ‬


‫عدل نوع اختياري‪.‬‬ ‫معلن ‪ :‬جزء من إعالن يتضمن االسم الذي تم تعريفه ُ‬

‫‪decltype‬‬ ‫نوع‪-‬معلن ‪ :‬محدد نوع يستنتج نوع متغري أو تعبري‪.‬‬

‫مهيِـئا رصيحا‪.‬‬
‫تهيئة افرتاضية ‪ :‬كيفية تهيئة الكائنات عند عدم إعطاءها ّ‬
‫تتحكم الفئة في كيفية تهيئة كائنات نوعها‪.‬‬
‫‪default initialization‬‬
‫يتم تهيئة كائنات النوع املدمج املعرف في النطاق العام على ‪ 0‬؛‬
‫بينما تلك املعرفة على النطاق املحلي تكون غري مهيأة ولها قيم غري معرفة‪.‬‬

‫اختياريا‪ .‬ال يجوز استخدام‬


‫ً‬ ‫تعريف ‪ :‬يخصص التخزين ملتغري نوع محدد ويهئي املتغري‬
‫‪definition‬‬
‫األسماء حىت يتم تعريفها أو اإلعالن عنها‪.‬‬

‫‪escape sequence‬‬ ‫تسلسل الهروب ‪:‬‬


‫آلية بديلة لتمثيل األحرف ‪ ،‬خاصة تلك اليت ليس لها تمثيالت قابلة للطباعة‪.‬‬
‫تسلسل الهروب عبارة عن رشطة مائلة للخلف متبوعة بحرف ‪،‬‬
‫أو ثالثة أو أقل من األرقام الثمانية ‪ ،‬أو ‪ x‬متبوعة برقم سدايس عرشي‪.‬‬

‫‪global scope‬‬ ‫نطاق عام ‪ :‬نطاق يقع خارج جميع النطاقات األخرى‪.‬‬

‫حارس العنوان ‪ :‬متغري معالج أولي يستخدم ملنع تضمني العنوان أكرث من مرة في‬
‫‪header guard‬‬
‫ملف واحد‪.‬‬

‫‪identifier‬‬ ‫معرف ‪ :‬تسلسل أحرف تشكل االسم‪ .‬املعرفات حساسة لحالة األحرف‪.‬‬
‫ّ‬

‫مهئي داخل‪-‬فئة ‪ُ :‬مقدم كجزء من إعالن عضو بيانات الفئة‪.‬‬


‫‪in-class initializer‬‬
‫يجب أن تتبع التهيئة داخل الفئة رمز = أو أن تكون محاطة داخل أقواس معقوفة‪.‬‬

‫‪in scope‬‬ ‫داخل نطاق ‪ :‬النطاق املرئي من النطاق الحالي‪.‬‬

‫‪initialized‬‬ ‫تمت التهيئة ‪ :‬متغري يعطى قيمة أولية عند تعريفه‪ .‬يجب تهيئة املتغريات عادة‪.‬‬

‫‪inner scope‬‬ ‫نطاق داخلي ‪ :‬النطاق الداخلي املتداخل داخل نطاق آخر‪.‬‬

‫‪integral types‬‬ ‫األنواع الصحيحة ‪ :‬انظر النوع الحسابي‪.‬‬

‫تهيئة القائمة ‪:‬‬


‫‪list initialization‬‬
‫املهيِـئات‪.‬‬
‫نموذج تهيئة يستخدم األقواس املتعرجة إلحاطة واحد أو أكرث من ّ‬

‫الحرفي ‪ :‬قيمة مثل رقم أو حرف أو سلسلة من األحرف‪ .‬ال يمكن تغيري القيمة‪.‬‬
‫‪literal‬‬ ‫يتم تضمني األحرف الحرفية في عالمات اقتباس مفردة ‪،‬‬
‫بينما يتم وضع السالسل الحرفية في عالميت اقتباس مزدوجتني‪.‬‬
‫‪local scope‬‬ ‫نطاق محلي ‪ :‬مرادف عام لنطاق الكتلة‪.‬‬

‫ثابت املستوى املنخفض ‪ :‬ثابت ليس من املستوى العالي‪.‬‬


‫‪low-level const‬‬
‫جزءا من النوع وال يتم تجاهله أب ًدا‪.‬‬
‫ً‬ ‫يعترب‬

‫‪member‬‬ ‫عضو ‪ :‬جزء من فئة‬

‫حرف غري قابل للطباعة ‪ :‬حرف بدون تمثيل مرئي ‪،‬‬


‫‪non-printable character‬‬
‫مثل حرف تحكم ومسافة للخلف وسطر جديد وما إلى ذلك‪.‬‬

‫‪null pointer‬‬ ‫مؤرش خالي ‪ :‬مؤرش قيمته ‪ .0‬املؤرش الخالي صالح لكنه ال يشري إلى أي كائن‪.‬‬

‫‪nullptr‬‬ ‫مؤرش‪-‬خالي ‪ :‬ثابت حرفي يشري إلى مؤرش خالي‪.‬‬

‫‪object‬‬ ‫كائن ‪ :‬منطقة من الذاكرة لها نوع‪ .‬املتغري هو كائن له اسم‪.‬‬

‫‪outer scope‬‬ ‫نطاق خارجي ‪ :‬نطاق يحيط بنطاق آخر‪.‬‬

‫‪pointer‬‬ ‫مؤرش ‪ :‬كائن يمكنه االحتفاظ بعنوان كائن أو عنوان ما بعد نهاية كائن أو صفر‪.‬‬

‫مؤرش لثابت ‪ :‬كائن يمكنه االحتفاظ بعنوان كائن ثابت‪.‬‬


‫‪pointer to const‬‬
‫ال يجوز استخدام مؤرش ثابت لتغيري قيمة الكائن الذي يشري إليه‪.‬‬

‫‪preprocessor‬‬ ‫معالج أولي ‪ :‬برنامج معالج يعمل كجزء من تجميع برنامج يس‪.++‬‬

‫متغري معالج أولي ‪ :‬متغري يديره املعالج اﻷولي‪.‬‬


‫‪preprocessor variable‬‬
‫يستبدل املعالج اﻷولي كل متغري معالج بقيمته قبل أن يتم تجميع برنامجنا‪.‬‬
‫‪reference‬‬ ‫مرجع ‪ :‬اسم مستعار لكائن آخر‪.‬‬

‫مرجع لثابت ‪ :‬مرجع ال يغري قيمة كائن يشري إليه‪.‬‬


‫‪reference to const‬‬
‫قد يرتبط املرجع لثابت بكائن ثابت ‪ ،‬أو كائن غري ثابت ‪ ،‬أو نتيجة تعبري‪.‬‬

‫‪Scope‬‬ ‫نطاق ‪ :‬جزء برنامج يكون لألسماء معىن فيها‪.‬‬


‫تحتوي يس‪ ++‬على عدة مستويات من النطاق هي‪:‬‬
‫‪global-‬‬
‫العام‪ : -‬األسماء املعرفة خارج أي نطاق آخر‬
‫‪class-‬‬
‫الفئة ‪ : -‬األسماء املعرفة داخل فئة‬
‫‪namespace-‬‬ ‫مساحة اﻻسم‪ : -‬األسماء املعرفة داخل مساحة اسم‬
‫‪block-‬‬ ‫الكتلة‪ : -‬األسماء املعرفة داخل كتلة‬

‫نطاقات متداخلة‪ :‬بمجرد اإلعالن عن اسم ‪،‬‬


‫‪Scopes nest.‬‬
‫يمكن الوصول إليه حىت نهاية النطاق الذي تم اإلعالن عنه فيه‪.‬‬

‫‪separate compilation‬‬ ‫التجميع املنفصل ‪ :‬القدرة على تقسيم الربنامج إلى عدة ملفات مصدر منفصلة‪.‬‬

‫‪signed‬‬ ‫قيما سالبة أو موجبة ‪ ،‬بما في ذلك الصفر‪.‬‬


‫إشارة ‪ :‬نوع عدد صحيح مؤرش يحمل ً‬

‫‪string‬‬ ‫سلسلة ‪ :‬نوع مكتبة تمثل تسلسالت متغرية الطول من األحرف‪.‬‬

‫‪struct‬‬ ‫بنية ‪ :‬كلمة مستخدمة لتعريف فئة‪.‬‬

‫مؤقت ‪ :‬كائن غري مسمى تم إنشاؤه بواسطة املرتجم أثناء تقييم تعبري‪.‬‬
‫‪temporary‬‬
‫يتواجد املؤقت حىت نهاية أكرب تعبري يحيط بالتعبري الذي تم إنشاؤه من أجله‪.‬‬

‫‪top-level const‬‬ ‫ثابت املستوى العالي ‪ :‬ثابت يحدد بأنه ال يمكن تغيري كائن‪.‬‬

‫نوع مستعار ‪ :‬اسم مستعار لنوع آخر‪ .‬يتم تعريفه من خالل إما تعريف‪-‬نوع أو إعالن‬
‫‪type alias‬‬
‫اسم مستعار‪.‬‬
‫فحص نوع ‪ :‬مصطلح يستخدم لوصف العملية اليت يتحقق من خاللها املرتجم من أن‬
‫‪type checking‬‬
‫الطريقة اليت يتم بها استخدام كائنات من نوع معني تتفق مع تعريف هذا النوع‪.‬‬

‫‪type specifier‬‬ ‫محدد نوع ‪ :‬اسم نوع‪.‬‬

‫يعرف اسما مستعارا ً لنوع آخر‪ .‬عندما يظهر تعريف‪-‬النوع في نوع‬


‫تعريف‪-‬نوع ‪ّ :‬‬
‫‪typedef‬‬
‫اﻹعالن األسايس ‪ ،‬فإن األسماء املعرفة في اإلعالن هي أسماء أنواع‪.‬‬

‫معرف ‪ :‬استخدام ال تحدد اللغة معىن له‪ .‬يعد االعتماد عن قصد أو بالخطأ على‬
‫غري ّ‬
‫‪undefined‬‬ ‫مصدرا غنياً ألخطاء وقت تشغيل يصعب تتبعها وملشكالت األمان‬
‫ً‬ ‫معرف‬ ‫غري‬ ‫سلوك‬
‫وقابلية النقل‪.‬‬

‫معرف بدون قيمة أولية‪ .‬بشكل عام ‪،‬‬


‫غري مهيأ ‪ :‬متغري ّ‬
‫‪uninitialized‬‬
‫تؤدي محاولة الوصول إلى قيمة متغري غري مهيأ إلى سلوك غري معرف‪.‬‬

‫بال_إشارة ‪ :‬نوع عدد صحيح بال_إشارة يحتوي فقط على قيم أكرب من أو تساوي‬
‫‪unsigned‬‬
‫الصفر‪.‬‬

‫متغري ‪ :‬كائن أو مرجع مسمى‪.‬‬


‫‪variable‬‬
‫في يس‪ ، ++‬يجب اإلعالن عن املتغريات قبل استخدامها‪.‬‬

‫نوع مؤرش يمكن أن يشري إلى أي نوع غري‪-‬ثابت‪.‬‬


‫*‪void‬‬
‫ال يجوز إلغاء اإلشارة إلى مثل هذه املؤرشات‪.‬‬

‫نوع لغرض خاص ‪ ،‬ليس له عمليات وال قيمة‪.‬‬


‫‪void type‬‬
‫ال يمكن تعريف متغري من النوع ‪.void‬‬

‫كلمة ‪ :‬الوحدة الطبيعية لحوسبة عدد صحيح على آلة معينة‪ .‬عادة ما تكون الكلمة‬
‫‪word‬‬
‫كبرية بما يكفي لتحتفظ بعنوان‪ .‬على جهاز ‪ 32‬بت ‪ ،‬تتكون الكلمة عاد ًة من ‪ 4‬بايت‪.‬‬

‫‪& operator‬‬ ‫عامل العنوان‪ .‬يعطي عنوان الكائن الذي يتم تطبيقه عليه‪.‬‬

‫عامل إلغاء املرجع‪ .‬يؤدي إلغاء مرجع عن مؤرش إلى إعادة الكائن الذي يشري إليه‬
‫‪* operator‬‬
‫املؤرش‪ .‬يؤدي التعيني إلى نتيجة مرجع مزال إلى تعيني قيمة جديدة للكائن األسايس‪.‬‬
‫‪# define‬‬ ‫توجيه املعالج اﻷولي الذي يعرف متغري املعالج اﻷولي‪.‬‬

‫‪# endif‬‬ ‫توجيه املعالج اﻷولي الذي ينهي منطقة ‪ ifdef#‬أو ‪.ifndef#‬‬

‫‪# ifdef‬‬ ‫توجيه املعالج اﻷولي الذي يحدد ما إذا كان متغريًا معرفاً أم ال‪.‬‬

‫‪# ifndef‬‬ ‫توجيه املعالج اﻷولي الذي يحدد ما إذا لم يتم تعريف متغري معني‪.‬‬

You might also like