سلسلة ++c للمحترفين الدرس 2: القيم مصنَّفة النوع في ++C


محمد الميداوي

القيم مصنَّفة النوع (Literals) هي عبارات تدل على ثابت تشير صياغته المحرفية إلى نوعه وقيمته، فمثلًا 42 هي قيمة مصنَّفة النوع بينما x ليست كذلك لأنك تحتاج إلى أن تنظر إلى تصريحها (declaration) لتعرف نوعها وتطالع الأسطر السابقة من الشيفرة لتعرف قيمتها. غير أن C++11 أتاحت للمستخدم إضافة قيم مصنَّفة النوع (User-Defined Literals)، وتُستخدم كاختصار لاستدعاءات الدوال.

سنستَعرض في هذا الدرس بعض القيم مصنَّفة النوع في C++‎، بدءًا بالقيمة this، ثم نستعرض بقية القيم في الأقسام التالية.

الكلمة المفتاحية this

تشير الكلمة المفتاحية this داخل دالة تابعة (member function) إلى نسخة من الصنف التي استدعيّت الدالة عليها، ولا يمكن استخدامها -أي this- في دالة تابعة ساكنة (static member function).

struct S {
    int x;
    S & operator = (const S & other) {
        x = other.x;
      
        // تعيد مرجعًا إلى الكائن الذي أسندَت إليه
        return *this;
    }
};

يعتمد نوع ‎this‎ على خاصية التأهيل الخاص بالتابع -سواء التأهيل المتطاير volatile أو الثابت constant- (بالإنجليزية اختصارًا: cv-qualification). فمثلًا، إن كان التابع ‎X::f‎ ثابتًا (‎const‎)، فإنّ نوع ‎this‎ داخل ‎f‎ سيكون مؤشرًا ثابتًا إلى ‎X‎ (أي ‎‎‎const X*‎‎)، لذلك لا يمكن استخدام ‎this‎ لتعديل الحقول غير الساكنة (non-static data members) من داخل دالة const تابعة. وبالمثل، يكتسب ‎this‎ التأهيل المتطاير (volatile qualification) من الدالة التي يظهر فيها. الإصدار ≥ C++11

يمكن أيضًا استخدام ‎this‎ في المُهيِّئ المعقوص (brace-or-equal-initializer) للحقول غير الساكنة.

struct S;
struct T {
    T(const S * s);
    // ...
};
struct S {
    // ...
    T t {
        this
    };
};

‎this‎ عبارة عن قيمة يمينيّة (rvalue)، أي أنّها تعبير لا يمكن أن يكون إلا في الطرف الأيمن من أيّ عملية إسناد (assignment)، لذلك لا يمكن إسناد قيمة لها.

الأعداد الصحيحة قيمةً ونوعًا (Integer literal)

تأخذ صياغة العدد الصحيح أحد الأشكال التالية:

  • نوع عشري (decimal-literal): وهو عدد مؤلف من رقم عشري يخالف الصفر (1، 2، 3، 4، 5، 6، 7، 8، 9)، متبوعًا برقم عشريّ واحد أو أكثر (0، 1، 2، 3، 4، 5، 6، 7، 8، 9)، مثلًا:
int d = 42;‎
  • نوع ثماني (octal-literal): وهو عدد يبدأ بالرقم صفر (0) متبوعًا برقم ثُمانيّ (octal) واحد أو أكثر (0، 1، 2، 3، 4، 5، 6، 7)، مثلًا:
int o = 052;
  • نوع ست عشري (hex-literal): وهو تسلسل الأحرف 0x أو 0X متبوعًا برقم واحد أو أكثر من الأرقام الست عشرية (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, A, b, B, c, C, d, D, e, E, f, F)، مثلًا:
int x = 0x2a; 
int X = 0X2A;‎
  • نوع ثنائي (binary-literal): (منذ C ++ 14) هو تسلسل الأحرف 0b أو 0B متبوعًا برقم ثنائي واحد أو أكثر (0، 1)، مثلا:
int b = 0b101010;‎
  • الأعداد الصحيحة الملحوقة غير المؤشّرة (unsigned-suffix)، قد تحتوي على أحد أو كلا الأمرين التاليين -قد يظهرا بدون ترتيب محدد في حالة وجودهما معًا:
    • الأعداد الملحوقة غير المُؤشرة (unsigned-suffix): هي أعداد ملحوقة بالحرف u أو U، مثلا:
unsigned int u_1 = 42u;‎
  • الأعداد الملحوقة الطويلة (long-suffix): هي أعداد ملحوقة بالحرف l أو L، أو الأعداد الملحوقة الطويلة المزدوجة (long-long-suffix)، وهي أعداد ملحوقة بالحرفين ll أو الحرفين LL (منذ C++11‎)

تأخذ المتغيرات التالية نفس القيمة:

unsigned long long l1 = 18446744073709550592ull; // C++11
unsigned long long l2 = 18'446'744'073'709'550'592llu; // C++14
unsigned long long l3 = 1844'6744'0737'0955'0592uLL; // C++14
unsigned long long l4 = 184467'440737'0'95505'92LLU; // C++14

ملاحظات

الأحرف الموجودة في الأعداد الصحيحة غير حساسة للحالة (case-insensitive): فتمثل الصيغتان 0xDeAdBaBeU و 0XdeadBABEu نفس العدد (الاستثناء الوحيد هو الأعداد الملحوقة الطويلة المزدوجة، والتي يمكن أن تكون إما ll أو LL، ولكن ليس lL أو Ll).

لا توجد صياغة لأعداد سالبة، فمثلًا تطبق تعابير مثل ‎-1 عامل السالب الأحادي (unary minus operator) على القيمة المُمثّلة بالقيمة مصنفَّة النوع (Literal)، والتي قد تتضمن تحويلات ضمنية للنوع (implicit type conversions).

في إصدارات C السابقة للإصدار C99 (ولكن ليس في C++‎)، يُسمح للقيم العشرية غير الملحوقة (unsuffixed decimal) من غير النوع long int أن تكون من النوع unsigned long int (عدد صحيح طويل عديم الإشارة).

تتصرف جميع الثوابت الصحيحة المؤشَّرة (signed integer constants) عند استخدامها في التعبيرات الشرطية -مثل ‎#if أو ‎#elif- كما لو كانت من النوع std::intmax_t، فيما تتصرف الثوابت الصحيحة غير المؤشرة كما لو كانت من النوع std::uintmax_t.

القيم المنطقية

الكلمة المفتاحية true

true هي كلمة مفتاحية تمثّل إحدى القيمتين المنطقيّتين المُمكنَتين للنوع ‎bool‎.

bool ok = true;
if (!f()) {
    ok = false;
    goto end;
}

الكلمة المفتاحية false

false هي كلمة مفتاحية تمثل إحدى القيمتين المنطقيّتين المُمكنتين للنوع ‎bool‎.

bool ok = true;
if (!f()) {
    ok = false;
    goto end;
}

الكلمة المفتاحية nullptr

الإصدار ≥ C++ 11

nullptr هي كلمة مفتاحية تمثل مؤشرًا ثابتًا فارغًا (null pointer constant)، ويمكن تحويلها إلى أيّ نوع من المؤشرات (Pointers) أو المؤشرات إلى الأعضاء (pointer-to-member)، وتعيد مؤشرًا فارغًا يشير إلى النوع الناتج.

Widget* p = new Widget();
delete p;
p = nullptr; // تفريغ المؤشر بعد الحذف

لاحظ أنّ ‎nullptr‎ ليست مؤشرًا بحد ذاتها، وإنّما هي نوع أساسي معروف باسم ‎std::nullptr_t‎.

void f(int * p);
template < class T >
    void g(T * p);
void h(std::nullptr_t p);
int main() {
    f(nullptr); // ok
    g(nullptr); // error
    h(nullptr); // ok
}

هذا الدرس جزء من سلسلة دروس عن C++‎.

ترجمة -وبتصرّف- للفصل Chapter 2: Literals من كتاب C++ Notes for Professionals

اقرأ أيضا





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن