Seringkali, seseorang membutuhkan beberapa jenis yang disebutkan bersama-sama. Terkadang, seseorang memiliki benturan nama. Dua solusi untuk hal ini muncul dalam pikiran: gunakan namespace, atau gunakan nama elemen enum 'lebih besar'. Namun, solusi namespace memiliki dua kemungkinan implementasi: kelas dummy dengan enum bersarang, atau namespace lengkap.
Saya mencari pro dan kontra dari ketiga pendekatan tersebut.
Contoh:
// oft seen hand-crafted name clash solution
enum eColors { cRed, cColorBlue, cGreen, cYellow, cColorsEnd };
enum eFeelings { cAngry, cFeelingBlue, cHappy, cFeelingsEnd };
void setPenColor( const eColors c ) {
switch (c) {
default: assert(false);
break; case cRed: //...
break; case cColorBlue: //...
//...
}
}
// (ab)using a class as a namespace
class Colors { enum e { cRed, cBlue, cGreen, cYellow, cEnd }; };
class Feelings { enum e { cAngry, cBlue, cHappy, cEnd }; };
void setPenColor( const Colors::e c ) {
switch (c) {
default: assert(false);
break; case Colors::cRed: //...
break; case Colors::cBlue: //...
//...
}
}
// a real namespace?
namespace Colors { enum e { cRed, cBlue, cGreen, cYellow, cEnd }; };
namespace Feelings { enum e { cAngry, cBlue, cHappy, cEnd }; };
void setPenColor( const Colors::e c ) {
switch (c) {
default: assert(false);
break; case Colors::cRed: //...
break; case Colors::cBlue: //...
//...
}
}
enum e {...}
, enum bisa anonim, yaituenum {...}
, yang jauh lebih masuk akal saat dibungkus dalam namespace atau kelas.Jawaban:
Jawaban C ++ 03 asli:
The manfaat dari
namespace
(atasclass
) adalah bahwa Anda dapat menggunakanusing
deklarasi ketika Anda ingin.The masalah dengan menggunakan
namespace
adalah bahwa ruang nama dapat diperluas di tempat lain dalam kode. Dalam proyek besar, Anda tidak akan dijamin bahwa dua enum berbeda tidak menganggap keduanya dipanggileFeelings
Untuk kode yang tampak lebih sederhana, saya menggunakan a
struct
, karena Anda mungkin ingin isinya menjadi publik.Jika Anda melakukan salah satu dari praktik ini, Anda berada di depan kurva dan mungkin tidak perlu meneliti ini lebih jauh.
Lebih baru, saran C ++ 11:
Jika Anda menggunakan C ++ 11 atau yang lebih baru,
enum class
secara implisit akan mencakup nilai enum dalam nama enum.Dengan
enum class
Anda akan kehilangan konversi implisit dan perbandingan dengan tipe integer, tetapi dalam praktiknya itu dapat membantu Anda menemukan kode yang ambigu atau buggy.sumber
FYI Di C ++ 0x ada sintaks baru untuk kasus seperti yang Anda sebutkan (lihat halaman wiki C ++ 0x )
sumber
Saya telah menggabungkan jawaban sebelumnya menjadi seperti ini: (EDIT: Ini hanya berguna untuk pra-C ++ 11. Jika Anda menggunakan C ++ 11, gunakan
enum class
)Saya punya satu file header besar yang berisi semua enum proyek saya, karena enum ini dibagi antara kelas pekerja dan tidak masuk akal untuk meletakkan enum di kelas pekerja itu sendiri.
The
struct
menghindari publik: gula sintaksis, dantypedef
memungkinkan Anda benar-benar mendeklarasikan variabel enum ini dalam kelas pekerja lain.Saya tidak berpikir menggunakan namespace membantu sama sekali. Mungkin ini karena saya programmer C #, dan di sana Anda harus menggunakan nama tipe enum saat merujuk nilai, jadi saya sudah terbiasa.
...
sumber
Saya pasti akan menghindari menggunakan kelas untuk ini; gunakan namespace sebagai gantinya. Pertanyaan intinya adalah apakah akan menggunakan namespace atau menggunakan id unik untuk nilai enum. Secara pribadi, saya akan menggunakan namespace sehingga id saya bisa lebih pendek dan mudah-mudahan lebih jelas. Kemudian kode aplikasi dapat menggunakan arahan 'using namespace' dan membuat semuanya lebih mudah dibaca.
Dari contoh Anda di atas:
sumber
Colors someColor = Red;
, karena namespace bukan merupakan suatu tipe. Anda harus menulisColors::e someColor = Red;
sebagai gantinya, yang cukup kontra-intuitif.Colors::e someColor
bahkan dengan astruct/class
jika Anda ingin menggunakannya dalamswitch
pernyataan? Jika Anda menggunakan anonimenum
maka sakelar tidak akan dapat mengevaluasi filestruct
.const e c
sepertinya sulit dibaca oleh saya :-) Jangan lakukan itu. Namun menggunakan namespace, boleh saja.Perbedaan antara menggunakan kelas atau namespace adalah bahwa kelas tidak dapat dibuka kembali seperti yang bisa dilakukan namespace. Hal ini menghindari kemungkinan bahwa namespace mungkin disalahgunakan di masa mendatang, tetapi ada juga masalah yang tidak dapat Anda tambahkan ke kumpulan enumerasi juga.
Manfaat yang mungkin untuk menggunakan kelas, adalah bahwa mereka dapat digunakan sebagai argumen jenis template, yang tidak berlaku untuk namespace:
Secara pribadi, saya bukan penggemar penggunaan , dan saya lebih suka nama yang sepenuhnya memenuhi syarat, jadi saya tidak benar-benar melihatnya sebagai nilai tambah untuk namespace. Namun, ini mungkin bukan keputusan terpenting yang akan Anda buat dalam proyek Anda!
sumber
Keuntungan menggunakan kelas adalah Anda dapat membangun kelas yang lengkap di atasnya.
Seperti yang ditunjukkan contoh di atas, dengan menggunakan kelas Anda dapat:
Perhatikan saja bahwa Anda perlu mendeklarasikan
operator enum_type()
agar C ++ tahu cara mengubah kelas Anda menjadi enum yang mendasarinya. Jika tidak, Anda tidak akan bisa meneruskan tipe keswitch
pernyataan.sumber
Karena enum tercakup dalam cakupannya, mungkin yang terbaik adalah membungkusnya dengan sesuatu untuk menghindari mencemari namespace global dan membantu menghindari benturan nama. Saya lebih suka namespace daripada kelas hanya karena
namespace
terasa seperti sekantong penyimpanan, sedangkanclass
terasa seperti objek yang kuat (lih. Debatstruct
vs.class
). Manfaat yang mungkin untuk namespace adalah bahwa ia dapat diperpanjang nanti - berguna jika Anda berurusan dengan kode pihak ketiga yang tidak dapat Anda modifikasi.Ini semua tentu saja bisa diperdebatkan ketika kita mendapatkan kelas enum dengan C ++ 0x.
sumber
Saya juga cenderung menyelesaikan enum saya di kelas.
Seperti yang diisyaratkan oleh Richard Corden, keuntungan dari sebuah kelas adalah ia merupakan tipe dalam pengertian c ++ sehingga Anda dapat menggunakannya dengan template.
Saya memiliki toolbox :: kelas Enum khusus untuk kebutuhan saya yang saya spesialisasikan untuk setiap template yang menyediakan fungsi dasar (terutama: memetakan nilai enum ke std :: string sehingga I / O lebih mudah dibaca).
Template kecil saya juga memiliki manfaat tambahan untuk benar-benar memeriksa nilai yang diizinkan. Kompiler agak lalai dalam memeriksa apakah nilainya benar-benar ada di enum:
Itu selalu mengganggu saya bahwa kompiler tidak akan menangkap ini, karena Anda ditinggalkan dengan nilai enum yang tidak masuk akal (dan Anda tidak akan mengharapkannya).
Demikian pula:
Sekali lagi main akan mengembalikan kesalahan.
Masalahnya adalah bahwa kompilator akan menyesuaikan enum dalam representasi terkecil yang tersedia (di sini kita membutuhkan 2 bit) dan semua yang cocok dalam representasi ini dianggap sebagai nilai yang valid.
Ada juga masalah bahwa terkadang Anda lebih suka memiliki loop pada nilai yang mungkin daripada sebuah sakelar sehingga Anda tidak perlu mengubah semua sakelar Anda setiap kali Anda menambahkan nilai ke enum.
Semua dalam semua penolong kecil saya benar-benar memudahkan hal-hal untuk enum saya (tentu saja, ini menambahkan beberapa overhead) dan itu hanya mungkin karena saya menyusun setiap enum di struct sendiri :)
sumber