Menu

C++ Enum'lar: enum class ile Düz enum Arasındaki Fark

C++ enum'larını öğren: nasıl tanımlanır, kapsamlı enum class neden düz enum'dan daha güvenlidir, özel temel değerler, enumeratörler üzerinde switch ve tam sayılara dönüştürme ile tam sayılardan dönüştürme.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

enum Ne İşe Yarar

Bir struct, birbiriyle ilişkili birkaç değeri tek bir nesnede gruplar. Bir enum ise farklı bir sorunu çözer: küçük, sabit bir seçenek kümesine isimler verir. 0'ın "kırmızı", 1'in "yeşil" ve 2'nin "mavi" anlamına geldiğini ezberlemek yerine Color::Red yazarsın ve derleyici seni dürüst tutar.

Bir değişken yalnızca birkaç adlandırılmış durumdan biri olabildiğinde —bir trafik ışığının rengi, bir iskambil takımı, bir bağlantı durumu— enum'a başvurmak, kodu kendi kendini belgeler hale getirir ve çıplak tam sayıların asla yakalayamayacağı yazım hatalarını ve eksik durumları derleyicinin yakalamasını sağlar.

Bir enum Tanımlamak

Modern C++'ta iki tür vardır. Neredeyse her zaman başvurman gerekenle başla: kapsamlı enum class. İsimleri listelersin ve her enumeratöre, enum'ın adı üzerinden :: ile erişilir:

Color::Green yazdığına, asla çıplak bir Green yazmadığına dikkat et. Değerlerin kendisi yalnızca etikettir; onları karşılaştırır, atar ve etrafta dolaştırırsın ama altındaki sayı nadiren umurundadır. Varsayılan olarak Red 0, Green 1 ve Blue 2'dir; sıfırdan başlayarak yukarı doğru sayar.

Düz enum ile enum class

Daha eski, kapsamsız enum (class anahtar sözcüğü olmadan) isimlerini doğrudan çevreleyen kapsama bırakır ve kendiliğinden int'e dönüşür. Bu kulağa pratik gelir ama iki gerçek soruna yol açar:

enum Color { Red, Green, Blue };
enum Fruit { Apple, Banana, Red };  // error: 'Red' already declared

enum Status { Active, Inactive };
int x = Active;          // compiles silently - is this what you meant?
if (Active == Banana) {  // compares unrelated enums via int - allowed!
}

Düz enumeratörler küresel isimler olduğundan, iki enum yalnızca bir etiketi paylaşarak bile çakışabilir. Ve int'e bozuldukları için derleyici, tamamen alakasız enum'ların değerlerini gönül rahatlığıyla karşılaştırır. Kapsamlı bir enum class her ikisini de düzeltir: isimler tipin içinde yaşar ve tip sessizce bir int'e dönüşmez:

Pratik kural: varsayılan olarak enum class kullan. Yalnızca özellikle örtük int dönüşümünü istediğinde —örneğin eski C tarzı bayrak sabitlerinde— düz bir enum'a geri dön.

Özel Değerler ve Temel Tip

Enumeratörlere açık sayılar atayabilirsin. Atamadan bıraktıklarının her biri bir öncekinden başlayarak yukarı doğru saymaya devam eder; bu da HTTP durum kodları veya bit bayrakları gibi şeyler için kullanışlıdır:

Her enum, bir tam sayı tipiyle desteklenir — varsayılan olarak int. Boyut önemli olduğunda, örneğin sıkıştırılmış bir yapıda çok sayıda enum saklarken veya bir veri yolu (wire) biçimine uyarken, onu daha küçük bir tipe sabitleyebilirsin:

Temel tipi seçmek, değerlerinin sığması gereken aralığı da garanti eder: bir uint8_t enum'ı 255'in üzerinde bir değer tutamaz.

enum ile int Arasında Dönüştürme

Kapsamlı bir enum class asla örtük olarak dönüşmez; bütün mesele de budur. Gerçekten sayıya ihtiyacın olduğunda —onu yazdırmak, bir diziyi indekslemek veya bir dosyadan okumak için— static_cast'e başvur. enum'dan int'e geçmek her zaman güvenlidir:

Bir int'i geri bir enum'a dönüştürmek tehlikeli olan yöndür. Dönüşüm, sayının gerçek bir enumeratöre karşılık geldiğini kontrol etmez; sana teknik olarak enum'ın adlandırılmış kümesinin dışında olan bir değer verir:

Suit s = static_cast<Suit>(2);   // fine - that's Clubs
Suit bad = static_cast<Suit>(99); // compiles, but 99 is not a valid Suit
// using `bad` in a switch or as an array index is a lurking bug

Tam sayı kullanıcı girdisinden veya bir dosyadan geliyorsa, dönüştürmeden önce aralığı kendin doğrula; aksi takdirde hiçbir case'in ele almadığı bir değer yaratırsın — ileride ortaya çıkacak sinsi bir tanımsız davranış kaynağı.

switch ile enum Kullanmak

Bir enum "sabit bir kümeden biri" olduğundan, bir switch ile kusursuz şekilde eşleşir. Her enumeratörü kapsadığında, daha sonra yeni bir değer ekleyip onu ele almayı unutursan birçok derleyici seni uyarır — çıplak tam sayılarla elde edemeyeceğin bedava bir güvenlik:

Bir tuzak: bir enumeratörün adını yazdırmanın yerleşik bir yolu yoktur. cout << TrafficLight::Red, kapsamlı bir enum için derlenmez ve düz bir enum için bile "Red" değil, sayıyı yazdırır. Yukarıdaki gibi küçük bir switch veya arama tablosu, bir enum'ı insan tarafından okunabilir bir dizeye dönüştürmenin olağan yoludur.

Sıradaki: İstisnalar

Enum'lar ve struct'lar, verinin nasıl göründüğünü modellemeni sağlar. Ama gerçek programlar bir de işlerin ters gitmesiyle uğraşmak zorundadır — açılmayan bir dosya, ayrıştırılamayan bir sayı, aralık dışındaki bir değer. C++ bu hata yollarını istisnalarla ele alır; o da bir sonraki sayfanın konusu.

Sıkça Sorulan Sorular

C++'ta enum ile enum class arasındaki fark nedir?

Düz bir enum, isimlerini çevreleyen kapsama sızdırır ve örtük olarak int'e dönüşür; bu da isim çakışmalarına ve istemeden yapılan karşılaştırmalara yol açar. Kapsamlı bir enum class ise isimlerini enum'ın içinde tutar (Color::Red) ve açık bir dönüşüm olmadan int'e dönüşmeyi reddeder. Modern C++'ta enum class tercih et; tip güvenlidir ve klasik tuzaklardan kaçınır.

C++'ta bir enum'ı int'e nasıl dönüştürürsün?

Düz bir enum örtük olarak dönüşür, bu yüzden int n = Red; doğrudan çalışır. Kapsamlı bir enum class ise açık bir dönüşüm gerektirir: int n = static_cast<int>(Color::Red);. Ters yönde gitmek için int'i geri dönüştür: Color c = static_cast<Color>(2);, ama dikkatli ol: çalışma zamanı, değerin geçerli bir enumeratör olup olmadığını kontrol etmez.

İlk C++ enum değeri hangi değerden başlar?

Varsayılan olarak ilk enumeratör 0'dır ve sonraki her biri bir öncekinden bir fazladır. Yani enum class Level { Low, Mid, High }; içinde Low 0, Mid 1 ve High 2'dir. Bu davranışı geçersiz kılmak için herhangi birine açık değerler atayabilirsin.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA