Enum vs Kesin yazılmış enum


84

C ++ programlamada acemiyim.

Bugün yeni bir konuyla karşılaşıyorum: güçlü bir şekilde yazılmış enum. Biraz araştırdım ama şimdiye kadar buna neden ihtiyacımız olduğunu ve bunun ne işe yaradığını bulamıyorum?

Örneğin, bizde:

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

Neden yazmamız gerekiyor:

enum class xyz{a, b, c};

Burada ne yapmaya çalışıyoruz? En önemli şüphem nasıl kullanılacağıdır. Anlamamı sağlayacak küçük bir örnek verebilir misiniz?

Yanıtlar:


114

Tamam, ilk örnek: eski tarz numaralandırmaların kendi kapsamları yoktur:

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!

İkincisi, örtük olarak integral türlerine dönüşürler ve bu da garip davranışlara yol açabilir:

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

Son olarak, C ++ 11 numaralandırmalarının temelindeki integral türünü belirtebilirsiniz:

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

Önceden, temel tür belirtilmiyordu ve bu, platformlar arasında uyumluluk sorunlarına neden olabilirdi. Düzenleme Yorumlarda, C ++ 11'de "eski stil" numaralandırmanın temeldeki integral türünü de belirtebileceğiniz belirtilmiştir.


Biz belirtmem gerekir mi / tanımlamak enum class Coloursve enum class Fruits. Çünkü VS 2010'da kodu yazdığımda "expects a defination or a tag name"altına bir hata atıyor class.
Rasmi Ranjan Nayak

Ayrıca: C ++ 11'deki "sıradan" enum için, C ++ 98'deki gibi varsayılan temel tür tanımlanmadı
bruziuz

2
Ayrıca: Temel alınan tür belirtilmişse, enum-s'nin ileri bildirimini yapabilirsiniz. C ++ 11, C ++ 98'deki sıradan numaralandırma için buna izin verilmez. Microsoft derleyici, enum'un ileri bildirimini yapmanıza izin verir, ancak bu yalnızca MS uzantısıdır, standart değildir (örneğin gcc buna izin vermez) Yani şimdi böyle bir şey yasaldır: enum ForwardDeclare: std :: uint8_t;
bruziuz

Örtülü olarak integral bir türe dönüşen numaralandırmaları kapsayabilir miyiz?
SS Anne

1
@SSAnne Hayır, örtük dönüştürme, güçlü bir şekilde yazılmış bir numaralandırma amacını geçersiz kılar. Bunun yerine dönüştürmeyi açıkça gerçekleştirmek için bir şablon işlevi tanımlayın; türü çıkarmak için std :: underlying_type <T> :: type kullanın.
David R

17

Bu IBM sayfasında numaralandırmalarla ilgili güzel bir makale var , çok ayrıntılı ve iyi yazılmış. İşte kısaca bazı önemli noktalar:

Kapsamlı numaralandırmalar, normal numaralandırmaların maruz kaldığı sınırlamaların çoğunu çözer: tam tür güvenliği, iyi tanımlanmış temel tür, kapsam sorunları ve ileriye dönük bildirim.

  • Kapsamlı numaralandırmaların diğer türlere tüm örtük dönüştürmelerine izin vermeyerek tür güvenliği elde edersiniz.
  • Yeni bir kapsam elde edersiniz ve numaralandırma artık kapsama alanında değildir ve kendisini ad çatışmalarından kurtarır.
  • Kapsamlı numaralandırmalar size numaralandırmanın temelini belirleme yeteneği sağlar ve kapsamlı numaralandırmalar için, belirtmemeyi seçerseniz varsayılan olarak int olur.
  • Sabit bir temel türe sahip herhangi bir enum ileri bildirilebilir.

2
Üçüncü ve dördüncü noktalar kapsamlı numaralandırmalara özel değildir; herhangi bir numaralandırmanın temelini belirtebilirsiniz.
Mike Seymour

1
PDF'nin daha az bozuk bir sürümüne bağlantısı olan var mı? İçindeki kod örnekleri PDF görüntüleyicilerimin hiçbirinde işlenmiyor, bu da hayal gücüne çok şey bırakıyor.
Sara Sinback

11

Değerleri, C-enums için değil enum class, gerçekten türdedir.enum classunderlying_type

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

Numaralandırma sınıfları ("yeni numaralandırmalar", "güçlü numaralandırmalar") geleneksel C ++ numaralandırmalarıyla üç sorunu ele alır:

  1. geleneksel enumsörtük olarak dönüştürür int, birisi bir numaralandırmanın bir tamsayı olarak davranmasını istemediğinde hatalara neden olur.
  2. geleneksel enumsnumaralayıcıları çevreleyen kapsama ihraç ederek ad çatışmalarına neden olur.
  3. Bir türünün temelindeki enumbelirtilemez, bu da karışıklığa, uyumluluk sorunlarına neden olur ve ileri bildirimi imkansız hale getirir.

enum class ("güçlü numaralandırmalar") güçlü bir şekilde yazılır ve kapsamları belirlenir:

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

Gösterildiği gibi, geleneksel numaralandırmalar her zamanki gibi çalışır, ancak artık isteğe bağlı olarak numaralandırmanın adıyla nitelendirebilirsiniz.

Yeni numaralandırmalar "enum sınıfı" dır çünkü geleneksel numaralandırmaların yönlerini (ad değerleri) sınıfların yönleriyle (kapsamlı üyeler ve dönüşüm yokluğu) birleştirirler.

Temel türü belirleyebilmek, daha basit birlikte çalışabilirliğe ve garantili numaralandırma boyutlarına izin verir:

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

Ayrıca numaralandırmaların ileriye doğru bildirimini sağlar:

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

Temel tür, işaretli veya işaretsiz tam sayı türlerinden biri olmalıdır; varsayılan değer int.

Standart kitaplıkta, enumsınıflar şunlar için kullanılır:

  1. Haritalama sistemleri belirli hata kodları: In <system_error>: enum class errc;
  2. İşaretçi güvenlik göstergeleri: Giriş <memory>:enum class pointer_safety { relaxed, preferred, strict };
  3. G / Ç akışı hataları: Giriş <iosfwd>:enum class io_errc { stream = 1 };
  4. Eşzamansız iletişim hatası işleme: Giriş <future>:enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied };

Bunların birçoğunun ==tanımlandığı gibi işleçleri vardır .


3

Enum Kapsamı

Numaralandırmalar, numaralandırıcılarını çevreleyen kapsama aktarır. Bunun iki dezavantajı vardır. Birincisi, aynı kapsamda bildirilen farklı numaralandırıcıların aynı ada sahip olması ad çatışmalarına yol açabilir; ikinci olarak, numaralandırıcı adı dahil olmak üzere tam nitelikli bir ada sahip bir numaralandırıcı kullanmak mümkün değildir.

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

select = ESet::a; // error
select = a;       // is ambigious
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.