[C++] لماذا تفضل طبقة التعداد على التعداد البسيط؟


Answers

من Bjarne Stroustrup's C ++ 11 FAQ :

تعالج فصول enum class ("التعدادات الجديدة" ، "التعدادات القوية") ثلاثة مشكلات في تعدادات C ++ التقليدية:

  • التوسعات التقليدية تحول ضمنيًا إلى int ، مما يتسبب في حدوث أخطاء عندما لا يرغب أحد الأشخاص في أن يعمل التعداد كعدد صحيح.
  • التعداد التقليدي تصدير العدادين إلى النطاق المحيط بها ، مما تسبب في اشتباكات الاسم.
  • لا يمكن تحديد النوع الأساسي من enum ، مما يسبب الارتباك ومشاكل التوافق ، ويجعل الإعلان المستحيل إلى الأمام.

إن التعدادات الجديدة هي "فئة التعداد" لأنها تجمع بين جوانب التعدادات التقليدية (قيم الأسماء) مع جوانب الطبقات (أعضاء نطاق معين وغياب التحويلات).

لذا ، كما ذكر من قبل المستخدمين الآخرين ، فإن "التعدادات القوية" تجعل الشفرة أكثر أمانًا.

يجب أن يكون النوع الأساسي enum "الكلاسيكي" عبارة عن عدد صحيح كبير بما يكفي ليتناسب مع جميع قيم enum ؛ هذا هو عادة int . كما يجب أن يكون كل نوع تعداد متوافق مع char أو نوع صحيح موقعة / غير موقعة.

هذا هو وصف واسع لما يجب أن يكون عليه enum الأساسي ، لذلك سيأخذ كل مترجم لوحده حول النوع الأساسي enum الكلاسيكي ، وفي بعض الأحيان قد تكون النتيجة مفاجئة.

على سبيل المثال ، رأيت رمزًا مثل هذه مجموعة من المرات:

enum E_MY_FAVOURITE_FRUITS
{
    E_APPLE      = 0x01,
    E_WATERMELON = 0x02,
    E_COCONUT    = 0x04,
    E_STRAWBERRY = 0x08,
    E_CHERRY     = 0x10,
    E_PINEAPPLE  = 0x20,
    E_BANANA     = 0x40,
    E_MANGO      = 0x80,
    E_MY_FAVOURITE_FRUITS_FORCE8 = 0xFF // 'Force' 8bits, how can you tell?
};

في الكود أعلاه ، يفكر بعض المبرمج الساذج بأن المخزن سوف يخزن قيم E_MY_FAVOURITE_FRUITS إلى نوع 8bit غير موقّع ... لكن لا يوجد ضمان حوله: قد يختار المترجم unsigned char أو int أو short ، أي من هذه الأنواع كبير بما فيه الكفاية لتناسب جميع القيم المشاهدة في enum . إن إضافة الحقل E_MY_FAVOURITE_FRUITS_FORCE8 هو عبء ولا يجبر المترجم على اتخاذ أي نوع من الاختيار حول النوع الأساسي enum .

إذا كان هناك جزء من التعليمة البرمجية يعتمد على حجم الكتابة و / أو يفترض أن E_MY_FAVOURITE_FRUITS سيكون له بعض العرض (على سبيل المثال: إجراءات التسلسل) قد تتصرف هذه التعليمة البرمجية بطرق غريبة استنادًا إلى أفكار المترجم.

ومما زاد الطين بلة ، إذا كان بعض زميل العمل يضيف بلا مبالاة قيمة جديدة إلى enum لدينا:

    E_DEVIL_FRUIT  = 0x100, // New fruit, with value greater than 8bits

المترجم لا يشكو من ذلك! إنه يقوم فقط بتغيير حجم الكتابة ليتناسب مع جميع قيم enum (بافتراض أن المجمع كان يستخدم أصغر نوع ممكن ، وهو افتراض لا يمكننا القيام به). هذه الإضافة البسيطة واللامبالاة إلى enum قد تفسد التعليمات البرمجية ذات الصلة.

بما أن C ++ 11 ممكن لتحديد النوع الأساسي لفئة enum و enum class (بفضل rdb ) ، فقد تمت معالجة هذه المشكلة بدقة:

enum class E_MY_FAVOURITE_FRUITS : unsigned char
{
    E_APPLE        = 0x01,
    E_WATERMELON   = 0x02,
    E_COCONUT      = 0x04,
    E_STRAWBERRY   = 0x08,
    E_CHERRY       = 0x10,
    E_PINEAPPLE    = 0x20,
    E_BANANA       = 0x40,
    E_MANGO        = 0x80,
    E_DEVIL_FRUIT  = 0x100, // Warning!: constant value truncated
};

تحديد النوع الأساسي إذا كان الحقل يحتوي على تعبير خارج نطاق هذا النوع سوف يشكو المجمع بدلاً من تغيير النوع الأساسي.

أعتقد أن هذا تحسن جيد في السلامة.

فلماذا تفضل طبقة التعداد على التعداد البسيط؟ ، إذا كان بإمكاننا اختيار النوع الأساسي لـ scoped ( enum class ) و enums ( enum ) enums ما الذي يجعل enum class خيارًا أفضل ؟:

  • لا يتحولون ضمنيًا إلى int .
  • لا تلوث مساحة الاسم المحيطة.
  • يمكن أن يتم الإعلان عنها.
Question

سمعت عدد قليل من الناس توصي باستخدام الطبقات التعدادية في C ++ بسبب سلامتهم النوعية .

ولكن ماذا يعني ذلك حقا؟




تستخدم التعدادات لتمثيل مجموعة من القيم الصحيحة.

تحدد الكلمة الأساسية class بعد enum أن التعداد تمت كتابته بشكلٍ كبير وأن أعداد التعداد الخاص به قد تم تحديدها. بهذه الطريقة تمنع الطبقات enum سوء الاستخدام غير المقصود للثوابت.

فمثلا:

enum class Animal{Dog, Cat, Tiger};
enum class Pets{Dog, Parrot};

هنا لا يمكننا خلط قيم الحيوانات والحيوانات الأليفة.

Animal a = Dog;       // Error: which DOG?    
Animal a = Pets::Dog  // Pets::Dog is not an Animal



Links