एक वर्ग के भीतर एक घोषणा की घोषणा


150

निम्नलिखित कोड स्निपेट में, ColorEnum Carके दायरे को सीमित करने और वैश्विक नामस्थान को "प्रदूषित" न करने का प्रयास करने के लिए , वर्ग के भीतर एनम को घोषित किया जाता है ।

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;

};

(१) क्या यह Colorएनम के दायरे को सीमित करने का एक अच्छा तरीका है ? या, क्या मुझे इसे Carकक्षा के बाहर घोषित करना चाहिए , लेकिन संभवतः अपने स्वयं के नामस्थान या संरचना के भीतर? मैं बस आज इस लेख के पार आया, जो बाद की वकालत करता है और चर्चा करता है कि एनम के बारे में कुछ अच्छे बिंदुओं पर: http://gamesfromwithin.com/stupid-c-tricks-2-better-enums

(२) इस उदाहरण में, जब कक्षा के भीतर काम करते हैं, तो क्या एनम को कोड करना सबसे अच्छा है Car::Color, या केवल Colorपर्याप्त होगा? (मुझे लगता है कि पूर्व बेहतर है, बस मामले Colorमें वैश्विक नाम स्थान में एक और एनम घोषित किया गया है। इस तरह, कम से कम, हम उस एनम के बारे में स्पष्ट हैं जिसका हम उल्लेख कर रहे हैं।)

जवाबों:


85
  1. यदि Colorकुछ ऐसा है जो सिर्फ Cars के लिए विशिष्ट है तो वह तरीका है जिससे आप इसके दायरे को सीमित कर देंगे। यदि आपके पास एक और Colorएनम है जिसे अन्य वर्ग उपयोग करते हैं तो आप इसे वैश्विक (या कम से कम बाहर Car) बना सकते हैं।

  2. इससे कोई फ़र्क नहीं पड़ता। यदि कोई वैश्विक है तो स्थानीय को अभी भी वैसे ही उपयोग किया जाता है क्योंकि यह वर्तमान दायरे के करीब है। ध्यान दें कि यदि आप वर्ग परिभाषा के बाहर उन फ़ंक्शन को परिभाषित करते हैं तो आपको Car::Colorफ़ंक्शन के इंटरफ़ेस में स्पष्ट रूप से निर्दिष्ट करने की आवश्यकता होगी ।


12
2. हाँ और नहीं। Car::Color getColor()लेकिन void Car::setColor(Color c)क्योंकि setColorहम पहले से ही निर्दिष्ट है।
मैथ्यू एम।

84

आजकल - C ++ 11 का उपयोग करके - आप इसके लिए enum class का उपयोग कर सकते हैं :

enum class Color { RED, BLUE, WHITE };

AFAII यह वही करता है जो आप चाहते हैं।


2
अफसोस की बात है कि यह सदस्य कार्यों की अनुमति नहीं देता है: stackoverflow.com/a/53284026/7395227
एंड्रियास

66

मैं निम्नलिखित दृष्टिकोण (नीचे कोड) पसंद करता हूं। यह "नाम स्थान प्रदूषण" समस्या को हल करता है, लेकिन यह बहुत अधिक प्रकार का है (आप असाइन नहीं कर सकते हैं और यहां तक ​​कि दो अलग-अलग गणना, या किसी अन्य अंतर्निहित प्रकार आदि के साथ अपने गणन की तुलना नहीं कर सकते हैं)।

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;
};

उपयोग:

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

मैं उपयोग की सुविधा के लिए मैक्रो बनाता हूं:

#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),

उपयोग:

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

कुछ संदर्भ:

  1. हर्ब सटर, जुम हिल्सॉप, सी / सी ++ उपयोगकर्ता जर्नल, 22 (5), मई 2004
  2. हर्ब सटर, डेविड ई। मिलर, ब्रेज़न स्ट्रॉस्ट्रुप स्ट्रांग टाइप एनम (संशोधन 3), जुलाई 2007

यह मुझे पंसद है। यह एनम को एक वैध मूल्य के साथ त्वरित करने के लिए मजबूर करता है। मुझे लगता है कि एक असाइनमेंट ऑपरेटर और कॉपी कंस्ट्रक्टर उपयोगी होगा। इसके अलावा t_ निजी होना चाहिए। मैक्रोज़ मैं बिना कर सकते हैं।
jmucchiello

मुझे भी यह पसंद है। संदर्भ के लिए धन्यवाद।
anio

1
आपने कहा: "यह बहुत अधिक प्रकार का है (आप असाइन नहीं कर सकते हैं और यहां तक ​​कि दो अलग-अलग गणनाओं की तुलना भी नहीं कर सकते हैं ..." । आपको क्यों लगता है कि यह एक अच्छी विशेषता है? मुझे लगता if(c2 == Color::Red )है कि यह उचित है और संकलन करना चाहिए, लेकिन आपके उदाहरण में नहीं। असाइनमेंट के लिए भी एक ही तर्क!
नवाज

3
@ नवाज़ c2दूसरे प्रकार के हैं ( Color2), तो आपको क्यों लगता है c2 == Color::Redऔर असाइनमेंट संकलित करने चाहिए? क्या होगा यदि Color::Red1 है, और Color2::Red2 है? का Color::Red == Color2::Redमूल्यांकन करना चाहिए trueया false? यदि आप गैर-प्रकार के एन्यूमरेटर्स को मिलाते हैं, तो आपके पास बुरा समय होगा।
विक्टर के

2
क्यों is_ टाइप t_; निजी?
झिंगम

7

सामान्य तौर पर, मैं हमेशा अपने एनम को एक में रखता हूं struct। मैंने "प्रीफ़िक्सिंग" सहित कई दिशानिर्देश देखे हैं।

enum Color
{
  Clr_Red,
  Clr_Yellow,
  Clr_Blue,
};

हमेशा यह सोचा कि यह लोगों की Cतुलना में दिशानिर्देशों की तरह अधिक C++है (संक्षिप्त नाम के कारण और नाम स्थान के कारण भी C++)।

इसलिए अब हमारे पास दो विकल्प होने की गुंजाइश है:

  • नामस्थान
  • structs / कक्षाएं

मैं व्यक्तिगत रूप से उपयोग करने के लिए तैयार हूं structक्योंकि इसका उपयोग टेम्पलेट प्रोग्रामिंग के लिए मापदंडों के रूप में किया जा सकता है, जबकि नाम स्थान में हेरफेर नहीं किया जा सकता है।

हेरफेर के उदाहरणों में शामिल हैं:

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

जो संरचना के अंदर enum के तत्वों की संख्या देता है T:)


3

यदि आप एक कोड लाइब्रेरी बना रहे हैं, तो मैं नाम स्थान का उपयोग करूंगा। हालाँकि, आप अभी भी उस नाम स्थान के अंदर केवल एक ही रंग जमा कर सकते हैं। यदि आपको एक एनम की आवश्यकता है जो एक सामान्य नाम का उपयोग कर सकती है, लेकिन विभिन्न वर्गों के लिए अलग-अलग स्थिरांक हो सकते हैं, तो अपने दृष्टिकोण का उपयोग करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.