Enum vs enum พิมพ์อย่างมาก


84

ฉันเป็นมือใหม่ในการเขียนโปรแกรม C ++

วันนี้ผมเจอกระทู้ใหม่: enumขอพิมพ์ ฉันได้ค้นคว้าข้อมูลมาบ้างแล้ว แต่จนถึงตอนนี้ฉันยังไม่สามารถหาคำตอบได้ว่าทำไมเราถึงต้องการสิ่งนี้และอะไรคือสิ่งที่ใช้เหมือนกัน?

ตัวอย่างเช่นหากเรามี:

enum xyz{a, b, c};
/*a = 0, b = 1, c = 2, (Typical C format)*/

ทำไมเราต้องเขียน:

enum class xyz{a, b, c};

เรากำลังพยายามทำอะไรที่นี่? ข้อสงสัยที่สำคัญที่สุดของฉันคือวิธีการใช้งาน คุณช่วยยกตัวอย่างเล็กน้อยซึ่งจะทำให้ฉันเข้าใจ

คำตอบ:


114

ตกลงตัวอย่างแรก: enums แบบเก่าไม่มีขอบเขตของตัวเอง:

enum Animals {Bear, Cat, Chicken};
enum Birds {Eagle, Duck, Chicken}; // error! Chicken has already been declared!

enum class Fruits { Apple, Pear, Orange };
enum class Colours { Blue, White, Orange }; // no problem!

ประการที่สองพวกเขาแปลงเป็นประเภทอินทิกรัลโดยปริยายซึ่งอาจนำไปสู่พฤติกรรมแปลก ๆ :

bool b = Bear && Duck; // what?

สุดท้ายคุณสามารถระบุประเภทอินทิกรัลของ C ++ 11 enums:

enum class Foo : char { A, B, C};

ก่อนหน้านี้ไม่ได้ระบุประเภทพื้นฐานซึ่งอาจทำให้เกิดปัญหาความเข้ากันได้ระหว่างแพลตฟอร์ม แก้ไขมีการระบุไว้ในความคิดเห็นว่าคุณยังสามารถระบุประเภทอินทิกรัลของ enum "แบบเก่า" ใน C ++ 11 ได้อีกด้วย


เราจำเป็นต้องประกาศ / กำหนดenum class Coloursและenum class Fruits. เพราะเมื่อฉันเขียนโค้ดใน VS 2010 มันแสดงข้อผิดพลาด"expects a defination or a tag name"ภายใต้class.
Rasmi Ranjan Nayak

นอกจากนี้: สำหรับ enum "ธรรมดา" ใน C ++ 11 เช่นเดียวกับในประเภทพื้นฐานเริ่มต้น C ++ 98 ไม่ได้กำหนดไว้
bruziuz

2
นอกจากนี้: คุณสามารถทำการประกาศ enum-s ไปข้างหน้าได้หากระบุประเภทพื้นฐานไว้ สำหรับ enum ธรรมดาใน C ++ 11 ไม่อนุญาตให้ใช้ C ++ 98 คอมไพเลอร์ของ Microsoft อนุญาตให้คุณทำการประกาศ enum ไปข้างหน้า แต่เป็นเพียงส่วนขยาย MS เท่านั้นซึ่งไม่ได้เป็นมาตรฐาน (เช่น gcc ไม่อนุญาต) ดังนั้นตอนนี้จึงเป็นกฎหมาย: enum ForwardDeclare: std :: uint8_t;
bruziuz

เราสามารถกำหนดขอบเขต enums ที่แปลงเป็นอินทิกรัลโดยปริยายได้หรือไม่?
SS Anne

1
@SSAnne ไม่การแปลงโดยนัยค่อนข้างจะเอาชนะวัตถุประสงค์ของ enum ที่พิมพ์อย่างรุนแรง กำหนดฟังก์ชันเทมเพลตเพื่อทำการแปลงแทนอย่างชัดเจน ใช้ std :: underlying_type <T> :: type เพื่อแยกประเภท
David R

17

มีบทความดีๆเกี่ยวกับ enums ในหน้า IBM นี้ซึ่งมีรายละเอียดมากและเขียนได้ดี ประเด็นสำคัญโดยสรุปมีดังนี้

ขอบเขตที่กำหนดไว้แก้ข้อ จำกัด ส่วนใหญ่ที่เกิดขึ้นโดย enums ทั่วไป: ความปลอดภัยของประเภทที่สมบูรณ์ประเภทพื้นฐานที่กำหนดไว้อย่างดีปัญหาขอบเขตและการประกาศไปข้างหน้า

  • คุณได้รับความปลอดภัยในการพิมพ์โดยการไม่อนุญาตการแปลง enums ที่กำหนดขอบเขตเป็นประเภทอื่นโดยปริยายทั้งหมด
  • คุณได้รับขอบเขตใหม่และ enum ไม่ได้อยู่ในขอบเขตการปิดล้อมอีกต่อไปช่วยตัวเองจากความขัดแย้งของชื่อ
  • ขอบเขต enums ช่วยให้คุณสามารถระบุชนิดพื้นฐานของการแจงนับและสำหรับการแจงนับที่กำหนดขอบเขตจะมีค่าเริ่มต้นเป็น int หากคุณเลือกที่จะไม่ระบุ
  • enum ใด ๆ ที่มีประเภทพื้นฐานคงที่สามารถประกาศไปข้างหน้า

2
จุดที่สามและสี่ไม่เฉพาะเจาะจงกับการแจงนับตามขอบเขต คุณสามารถระบุประเภทพื้นฐานของการแจงนับใด ๆ
Mike Seymour

1
ใครมีลิงค์ไปยัง PDF เวอร์ชันเสียน้อย ตัวอย่างโค้ดในนั้นไม่แสดงในโปรแกรมดู PDF ของฉันซึ่งทำให้จินตนาการได้มาก
Sara Sinback

11

ค่าของenum classเป็นประเภทจริงๆenum classไม่ใช่underlying_typeสำหรับ C-enums

enum xyz { a, b, c};
enum class xyz_c { d, f, e };

void f(xyz x)
{
}

void f_c(xyz_c x)
{
}

// OK.
f(0);
// OK for C++03 and C++11.
f(a);
// OK with C++11.
f(xyz::a);
// ERROR.
f_c(0);
// OK.
f_c(xyz_c::d);

5

คลาส enum ("new enums", "strong enums") ช่วยแก้ปัญหาสามประการเกี่ยวกับการแจงนับ C ++ แบบเดิม:

  1. การชุมนุมenumsโดยปริยายแปลงintที่ก่อให้เกิดข้อผิดพลาดเมื่อมีคนไม่ต้องการการแจงนับจะทำหน้าที่เป็นจำนวนเต็ม
  2. การenumsส่งออกตัวนับแบบเดิมไปยังขอบเขตโดยรอบทำให้เกิดการขัดแย้งกัน
  3. enumไม่สามารถระบุประเภทพื้นฐานของ an ได้ทำให้เกิดความสับสนปัญหาความเข้ากันได้และทำให้ไม่สามารถประกาศล่วงหน้าได้

enum class ("strong enums") ถูกพิมพ์อย่างรุนแรงและกำหนดขอบเขต:

enum Alert { green, yellow, orange, red }; // traditional enum

enum class Color { red, blue };   // scoped and strongly typed enum
                                  // no export of enumerator names into enclosing scope
                                  // no implicit conversion to int
enum class TrafficLight { red, yellow, green };

Alert a = 7;              // error (as ever in C++)
Color c = 7;              // error: no int->Color conversion

int a2 = red;             // ok: Alert->int conversion
int a3 = Alert::red;      // error in C++98; ok in C++11
int a4 = blue;            // error: blue not in scope
int a5 = Color::blue;     // error: not Color->int conversion

Color a6 = Color::blue;   // ok

ดังที่แสดงไว้ enums แบบดั้งเดิมทำงานได้ตามปกติ แต่ตอนนี้คุณสามารถเลือกที่จะมีคุณสมบัติตามชื่อของ enum ได้

enums ใหม่คือ "enum class" เนื่องจากรวมแง่มุมของการแจงนับแบบดั้งเดิม (ค่าชื่อ) กับแง่มุมของคลาส (สมาชิกที่กำหนดขอบเขตและไม่มีการแปลง)

ความสามารถในการระบุประเภทพื้นฐานทำให้สามารถทำงานร่วมกันได้ง่ายขึ้นและขนาดการแจงนับที่รับประกัน:

enum class Color : char { red, blue };  // compact representation

enum class TrafficLight { red, yellow, green };  // by default, the underlying type is int

enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U };   // how big is an E?
                                                 // (whatever the old rules say;
                                                 // i.e. "implementation defined")

enum EE : unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U };   // now we can be specific

นอกจากนี้ยังเปิดใช้งานการประกาศ enums ล่วงหน้า:

enum class Color_code : char;     // (forward) declaration
void foobar(Color_code* p);       // use of forward declaration
// ...
enum class Color_code : char { red, yellow, green, blue }; // definition

ประเภทที่อยู่ภายใต้ต้องเป็นหนึ่งในประเภทจำนวนเต็มที่ลงชื่อหรือไม่ได้ลงชื่อ intเริ่มต้นคือ

ในไลบรารีมาตรฐานenumคลาสใช้สำหรับ:

  1. รหัสข้อผิดพลาดเฉพาะของระบบการแมป: ใน<system_error>: enum class errc;
  2. ตัวชี้ความปลอดภัย: ใน<memory>:enum class pointer_safety { relaxed, preferred, strict };
  3. ข้อผิดพลาดในการสตรีม I / O: ใน<iosfwd>:enum class io_errc { stream = 1 };
  4. การจัดการข้อผิดพลาดการสื่อสารแบบอะซิงโครนัส: ใน<future>:enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied };

หลายตัวมีตัวดำเนินการเช่นที่==กำหนดไว้


3

ขอบเขต Enum

การแจงนับส่งออกตัวแจงนับไปยังขอบเขตโดยรอบ สิ่งนี้มีข้อบกพร่องสองประการ ประการแรกอาจนำไปสู่การปะทะกันของชื่อหากผู้แจงนับสองคนใน enums ต่างกันที่ประกาศในขอบเขตเดียวกันมีชื่อเดียวกัน ประการที่สองเป็นไปไม่ได้ที่จะใช้ตัวแจงนับที่มีชื่อแบบเต็มรวมถึงชื่อ enum

enum ESet {a0, a, a1, b1, c3};
enum EAlpha{a, b, c}

select = ESet::a; // error
select = a;       // is ambigious
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.