Sınıf içindeki bir numaralandırma bildirme


151

Aşağıdaki kod snippet'inde, Colornumaralandırmanın Carkapsamını sınırlamak ve genel ad alanını "kirletmemek" için sınıflandırma sınıf içinde bildirilir .

class Car
{
public:

   enum Color
   {
      RED,
      BLUE,
      WHITE
   };

   void SetColor( Car::Color color )
   {
      _color = color;
   }

   Car::Color GetColor() const
   {
      return _color;
   }

private:

   Car::Color _color;

};

(1) Bu, Colornumaralandırma kapsamını sınırlamanın iyi bir yolu mu? Yoksa, Carsınıfın dışında , ancak muhtemelen kendi ad alanı veya yapısı içinde mi ilan etmeliyim ? Bugün bu makaleye geldim, ikincisini savunuyor ve numaralandırmalar hakkında bazı güzel noktaları tartışıyor: http://gamesfromwithin.com/stupid-c-tricks-2-better-enums .

(2) Bu örnekte, sınıf içinde çalışırken , sıralamayı en iyi şekilde kodlamak mı Car::Coloryoksa Coloryeterli olur mu? (Birincisinin daha iyi olduğunu düşünüyorum, Colorküresel ad alanında başka bir numaralandırma bildirilmesi durumunda . En azından, bahsettiğimiz numaralandırma hakkında açıkız.)

Yanıtlar:


86
  1. Eğer Colorsadece Cars'ye özgü bir şey varsa , o zaman kapsamını sınırlandırırsınız. ColorDiğer sınıfların kullandığı başka bir numaralandırma yapacaksanız, onu global (veya en azından dışarıda Car) yapabilirsiniz.

  2. Fark yaratmıyor. Küresel bir tane varsa, o zaman yerel olan mevcut kapsama daha yakın olduğu için yine de kullanılır. Bu işlevi sınıf tanımının dışında tanımlarsanız Car::Color, işlevin arabiriminde açıkça belirtmeniz gerektiğini unutmayın .


12
2. Evet ve hayır. Car::Color getColor()ama void Car::setColor(Color c)çünkü setColorbiz zaten belirtici var.
Matthieu M.Mar


66

Aşağıdaki yaklaşımı tercih ediyorum (aşağıdaki kod). "Ad alanı kirliliği" sorununu çözer, ama aynı zamanda çok daha tipiktir (iki farklı numaralandırma ya da diğer yerleşik türlerle numaralandırmayı atayamaz ve hatta karşılaştıramazsınız).

struct Color
{
    enum Type
    {
        Red, Green, Black
    };
    Type t_;
    Color(Type t) : t_(t) {}
    operator Type () const {return t_;}
private:
   //prevent automatic conversion for any other built-in types such as bool, int, etc
   template<typename T>
    operator T () const;
};

Kullanımı:

Color c = Color::Red;
switch(c)
{
   case Color::Red:
     //некоторый код
   break;
}
Color2 c2 = Color2::Green;
c2 = c; //error
c2 = 3; //error
if (c2 == Color::Red ) {} //error
If (c2) {} error

Kullanımı kolaylaştırmak için makro oluşturuyorum:

#define DEFINE_SIMPLE_ENUM(EnumName, seq) \
struct EnumName {\
   enum type \
   { \
      BOOST_PP_SEQ_FOR_EACH_I(DEFINE_SIMPLE_ENUM_VAL, EnumName, seq)\
   }; \
   type v; \
   EnumName(type v) : v(v) {} \
   operator type() const {return v;} \
private: \
    template<typename T> \
    operator T () const;};\

#define DEFINE_SIMPLE_ENUM_VAL(r, data, i, record) \
    BOOST_PP_TUPLE_ELEM(2, 0, record) = BOOST_PP_TUPLE_ELEM(2, 1, record),

Kullanımı:

DEFINE_SIMPLE_ENUM(Color,
             ((Red, 1))
             ((Green, 3))
             )

Bazı referanslar:

  1. Herb Sutter, Jum Hyslop, C / C ++ Kullanıcı Günlüğü, 22 (5), Mayıs 2004
  2. Herb Sutter, David E. Miller, Bjarne Stroustrup Güçlü Yazılan Numaralandırmalar (revizyon 3), Temmuz 2007

Bunu severim. Ayrıca, numaralandırmanın geçerli bir değerle somutlaştırılmasını zorlar. Ben bir atama operatörü ve kopya yapıcı yararlı olacağını düşünüyorum. Ayrıca t_ özel olmalıdır. Ben olmadan yapabileceğim makrolar.
jmucchiello

Ben de beğendim. Referanslar için teşekkürler.
anio

1
Dedin: "Ayrıca çok daha türgüvenli sen atama yapamaz ve hatta iki farklı numaralandırma karşılaştırın (olduğunu ..." Neden Bence bu iyi bir özellik olduğunu düşünüyorum.? if(c2 == Color::Red )Makul ve derlemek gerekir, ancak sizin örnekte o Görev için de aynı argüman!
Nawaz

3
@Nawaz c2başka tipte ( Color2), öyleyse neden c2 == Color::Redödevlerin derlenmesi gerektiğini düşünüyorsunuz ? Color::Red1 ve Color2::Red2 ise ne olur ? Meli Color::Red == Color2::Rediçin değerlendirmek trueya false? Normal olmayan sayıcıları karıştırırsanız, kötü zaman geçireceksiniz.
Victor K

2
Neden t_ Tipi değil; özel?
Zingam

7

Genel olarak, numaralandırmalarımı her zaman bir struct. "Ön ek" dahil olmak üzere çeşitli yönergeler gördüm.

enum Color
{
  Clr_Red,
  Clr_Yellow,
  Clr_Blue,
};

Bunun her Czamankinden daha çok yönergeler gibi göründüğünü düşündüm C++(biri kısaltma ve ayrıca ad alanları nedeniyle C++).

Kapsamı sınırlamak için şimdi iki alternatifimiz var:

  • ad
  • yapılar / sınıfları

Ben şahsen kullanmak eğilimindedir structçünkü bir isim alanı manipüle edilemez iken şablon programlama için parametre olarak kullanılabilir.

Manipülasyon örnekleri şunları içerir:

template <class T>
size_t number() { /**/ }

bu yapı içindeki numaralandırma elemanlarının sayısını döndürür T:)


3

Bir kod kitaplığı oluşturuyorsanız, ad alanını kullanırdım. Ancak, yine de bu ad alanının içinde yalnızca bir Renk numaralandırma olabilir. Ortak bir ad kullanabilen, ancak farklı sınıflar için farklı sabitlere sahip olabilen bir numaralandırmaya ihtiyacınız varsa, yaklaşımınızı kullanın.

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.