बेस एनुम क्लास इनहेरिटेंस


79

वहाँ एक पैटर्न है जहाँ मैं सी + + में एक और एनम से Enum वारिस कर सकते हैं ??

ऐसा कुछ:

enum eBase 
{
   one=1, two, three
};


enum eDerived: public eBase
{
   four=4, five, six
};

जवाबों:


67

संभव नहीं। एनम के साथ कोई विरासत नहीं है।

इसके बजाय आप नामित कॉन्स्ट इन्ट्स वाली कक्षाओं का उपयोग कर सकते हैं।

उदाहरण:

class Colors
{
public:
  static const int RED = 1;
  static const int GREEN = 2;
};

class RGB : public Colors
{
  static const int BLUE = 10;
};


class FourColors : public Colors
{
public:
  static const int ORANGE = 100;
  static const int PURPLE = 101;
};

क्या इस समाधान में कोई समस्या है? उदाहरण के लिए, (मुझे पॉलीमोर्फिज़्म की गहरी समझ नहीं है) क्या वेक्टर <कलर्स> और उपयोग, p = std :: find (mycolors, mycolor + length, Colors :: ORANGE)?
जेस्पेस्टाना

1
@jespestana नहीं, आप Colorsवर्ग उदाहरणों का उपयोग नहीं करेंगे । आप केवल स्थैतिक कांस्टेबल सदस्यों में अंतर मान का उपयोग करते हैं।
jiandingzhe

अगर मैं तुम्हें ठीक समझूं; फिर, मुझे एक वेक्टर <Int> कंटेनर का उपयोग करना होगा। लेकिन मैं अभी भी लिख सकूंगा: p = std :: find (mycolors, mycolor + length, Colors, ORD) ;. सही?
जेस्टेस्टाना

1
@jespestana बिल्कुल। अगर खोज एक बहुत ही सामान्य ऑपरेशन है, तो एक फ्लैट_सेट या ओपन एड्रेस हैश सेट का उपयोग करने पर विचार करें।
v.oddou

1
पुन :: इस समाधान के साथ कोई समस्या है? यह समस्याग्रस्त हो सकता है कि ये मान किसी विशिष्ट प्रकार के नहीं हैं। आप एक फ़ंक्शन नहीं लिख सकते हैं जो एक की उम्मीद करता है Color, जैसे आप एक के लिए कर सकते हैं enum
ड्रू डॉर्मन

93
#include <iostream>
#include <ostream>

class Enum
{
public:
    enum
    {
        One = 1,
        Two,
        Last
    };
};

class EnumDeriv : public Enum
{
public:
    enum
    {
        Three = Enum::Last,
        Four,
        Five
    };
};

int main()
{
    std::cout << EnumDeriv::One << std::endl;
    std::cout << EnumDeriv::Four << std::endl;
    return 0;
}

1
मैं उलझन में हूं! फिर आप चर या फ़ंक्शन तर्क में Enum प्रकारों को कैसे संदर्भित करेंगे, और आप यह कैसे सुनिश्चित करेंगे कि Enum की अपेक्षा कर रहे एक फ़ंक्शन को EnumDeriv नहीं दिया गया था?
सिद्देशो बॉब

21
यह काम नहीं करेगा। जब आप कुछ कार्यों को परिभाषित करते हैं int basic(EnumBase b) { return b; }और int derived(EnumDeriv d) { return d; }, उन प्रकारों को परिवर्तनीय नहीं किया जाएगा int, हालांकि सादे एनम हैं। और जब आप इस तरह के एक भी सरल कोड की कोशिश करते हैं: cout << basic(EnumBase::One) << endl;तो, आपको एक त्रुटि मिलेगी conversion from ‘EnumBase::<anonymous enum>’ to non-scalar type ‘EnumBase’ requested:। कुछ रूपांतरण ऑपरेटरों को जोड़कर शायद उन समस्याओं को दूर किया जा सकता है।
सासुक

10

आप सीधे ऐसा नहीं कर सकते, लेकिन आप इस लेख से समाधान का उपयोग करने की कोशिश कर सकते हैं ।

मुख्य विचार सहायक टेम्प्लेट क्लास का उपयोग करना है, जो एनम मान रखता है और जिसमें टाइप कास्ट ऑपरेटर होता है। यह मानते हुए कि एनम के लिए अंतर्निहित प्रकार intआप इस धारक वर्ग को एनम के बजाय अपने कोड में मूल रूप से उपयोग कर सकते हैं।


हालांकि यह कोड स्निपेट प्रश्न को हल कर सकता है, जिसमें स्पष्टीकरण सहित वास्तव में आपकी पोस्ट की गुणवत्ता में सुधार करने में मदद करता है। याद रखें कि आप भविष्य में पाठकों के लिए प्रश्न का उत्तर दे रहे हैं, और वे लोग आपके कोड सुझाव के कारणों को नहीं जान सकते हैं।
नाथनऑलिवर

यह एक महान जवाब है; यह उन उदाहरणों में से एक है "समस्या के बारे में एक अलग तरीके से सोचें" और एक टेम्पलेट का उपयोग करने का विचार वास्तव में बिल को फिट बैठता है।
डेन-जेसन

इस विज़-ए-विज़ टेम्पलेट्स के कुछ समाधानों पर भी एक नज़र डालें: stackoverflow.com/questions/5871722/…
Den-Jason

5

दुर्भाग्य से यह C ++ 14 में संभव नहीं है। मुझे उम्मीद है कि हमारे पास C ++ 17 में ऐसी भाषा सुविधा होगी। जैसा कि आप पहले से ही अपनी समस्या के लिए कुछ समाधान मैं एक समाधान प्रदान नहीं करेगा।

मैं यह बताना चाहता हूं कि शब्द "विस्तार" होना चाहिए न कि "वंशानुक्रम"। विस्तार अधिक मूल्यों के लिए अनुमति देता है (जैसा कि आप अपने उदाहरण में 3 से 6 मानों से कूद रहे हैं) जबकि विरासत का अर्थ है किसी दिए गए आधार वर्ग में अधिक अवरोध डालना ताकि संभावनाओं का समूह सिकुड़ जाए। इसलिए, संभावित कास्टिंग विरासत से बिल्कुल विपरीत काम करेगी। आप व्युत्पन्न वर्ग को आधार वर्ग में डाल सकते हैं, न कि वर्ग उत्तराधिकार के साथ उलटा। लेकिन एक्सटेंशन होने पर आपको "क्लास" को अपने एक्सटेंशन में ले जाने में सक्षम होना चाहिए, न कि इसके विपरीत। मैं कह रहा हूँ "चाहिए" क्योंकि, जैसा कि मैंने कहा कि इस तरह की भाषा की सुविधा अभी भी मौजूद नहीं है।


ध्यान दें कि extendsएफिल भाषा में वंशानुक्रम के लिए एक कीवर्ड है।
चीयर्स एंड हीथ। -

आप सही हैं क्योंकि इस मामले में लिस्कोव प्रतिस्थापन सिद्धांत का सम्मान नहीं किया जाता है। कॉमाइट इस वजह से वंशानुक्रम की तरह दिखने वाले समाधान को स्वीकार नहीं करेगा।
v.oddou

4

इस बारे में कैसा है? ठीक है एक उदाहरण हर संभव मूल्य के लिए बनाया गया है, लेकिन इसके अलावा यह बहुत लचीला है। क्या कोई डाउनसाइड है?

.h:

class BaseEnum
{
public:
  static const BaseEnum ONE;
  static const BaseEnum TWO;

  bool operator==(const BaseEnum& other);

protected:
  BaseEnum() : i(maxI++) {}
  const int i;
  static int maxI;
};

class DerivedEnum : public BaseEnum
{
public:
  static const DerivedEnum THREE;
};

.cpp:

int BaseEnum::maxI = 0;

bool BaseEnum::operator==(const BaseEnum& other) {
  return i == other.i;
}

const BaseEnum BaseEnum::ONE;
const BaseEnum BaseEnum::TWO;
const DerivedEnum DerivedEnum::THREE;

उपयोग:

BaseEnum e = DerivedEnum::THREE;

if (e == DerivedEnum::THREE) {
    std::cerr << "equal" << std::endl;
}

एकमात्र नुकसान जो मैं देख सकता हूं वह उच्च मेमोरी खपत है और इसे कोड की अधिक लाइनों की आवश्यकता है। लेकिन मैं आपके समाधान की कोशिश करूंगा।
निट्सची

मैंने BaseEnum::iसार्वजनिक और BaseEnum::maxIनिजी भी किया ।
निट्सची

संरक्षित डिफॉल्ट कंस्ट्रक्टर एक समस्या हो सकती है जब एनम को 3 डी मैक्रोज़ या टेम्प्लेट में उपयोग करने की आवश्यकता होती है जो कि डिफॉल्ट कंस्ट्रक्टर की आवश्यकता होती है।
नाइट्सची

3

यदि आप enumव्युत्पन्न वर्ग में एक ही नाम के साथ परिभाषित करते हैं और इसे enumआधार वर्ग में संवाददाता के अंतिम आइटम से शुरू करते हैं , तो आप लगभग वही प्राप्त करेंगे जो आप चाहते हैं - विरासत में मिला एनम। इस कोड को देखें:

class Base
{
public:
    enum ErrorType
    {
        GeneralError,
        NoMemory,
        FileNotFound,
        LastItem,
    };
};

class Inherited: public Base
{
public:
    enum ErrorType
    {
        SocketError = Base::LastItem,
        NotEnoughBandwidth,
    };
};

1
कोड संकलित होने के बावजूद, आप इसका उपयोग नहीं कर पाएंगे, क्योंकि कंपाइलर आधार से परिवर्तित नहीं कर पाएगा :: ErrorType Inherited :: ErrorType।
बावेजा

1
@bavaza, निश्चित रूप से, आपको मापदंडों के रूप में उनके मूल्यों को पारित करते समय एनम के बजाय पूर्णांक का उपयोग करना चाहिए।
हसप्यूमुलेटर

2

जैसा कि कहा गया है bayda, Enum की (और / या नहीं) की कार्यक्षमता होनी चाहिए, इसलिए मैंने निम्नलिखित Mykola Golubyevप्रतिक्रिया को स्वीकार करते हुए आपके प्रश्न के लिए निम्नलिखित दृष्टिकोण लिया है :

typedef struct
{
    enum
    {
        ONE = 1,
        TWO,
        LAST
    };
}BaseEnum;

typedef struct : public BaseEnum
{
    enum
    {
        THREE = BaseEnum::LAST,
        FOUR,
        FIVE
    };
}DerivedEnum;

2
इस समाधान के साथ कुछ समस्याएं हैं। सबसे पहले, आप बेसिन को LAST के साथ प्रदूषित कर रहे हैं जो वास्तव में DerivedEnum के लिए शुरुआती बिंदु सेट करने के अलावा अन्य मौजूद नहीं है। दूसरा, क्या होगा अगर मैं बेसइनम में कुछ मूल्यों को स्पष्ट रूप से निर्धारित करना चाहता हूं जो कि डेरिवेनमम मूल्यों से टकराएगा? वैसे भी, यह शायद सबसे अच्छा है जो हम C ++ 14 में कर सकते हैं।
Огћен Шобаји

जैसा कि मैंने कहा, यह एक पिछले उदाहरण से अनुकूलित है, इसलिए इसे पूर्णता के लिए जिस तरह से व्यक्त किया गया है, यह मेरी चिंता नहीं है कि पिछले पोस्टर में उनके उदाहरण में तार्किक मुद्दे हैं
सतर्कता

2

विस्तार योग्य गणना बनाने के लिए आप प्रोजेक्ट SuperEnum का उपयोग कर सकते हैं ।

/*** my_enum.h ***/
class MyEnum: public SuperEnum<MyEnum>
{
public:
    MyEnum() {}
    explicit MyEnum(const int &value): SuperEnum(value) {}

    static const MyEnum element1;
    static const MyEnum element2;
    static const MyEnum element3;
};

/*** my_enum.cpp ***/
const MyEnum MyEnum::element1(1);
const MyEnum MyEnum::element2;
const MyEnum MyEnum::element3;

/*** my_enum2.h ***/
class MyEnum2: public MyEnum
{
public:
    MyEnum2() {}
    explicit MyEnum2(const int &value): MyEnum(value) {}

    static const MyEnum2 element4;
    static const MyEnum2 element5;
};

/*** my_enum2.cpp ***/
const MyEnum2 MyEnum2::element4;
const MyEnum2 MyEnum2::element5;

/*** main.cpp ***/
std::cout << MyEnum2::element3;
// Output: 3

1
हालांकि एक पुरानी पोस्ट है, मुझे लगता है कि यह एक जवाब के लायक है। मैं डिफ़ॉल्ट कंस्ट्रक्टर से छुटकारा पाने और स्पष्ट कंस्ट्रक्टर को निजी में स्थानांतरित करने का सुझाव दूंगा। आप अभी भी जिस तरह से कर रहे हैं, उसमें वैरिएबल को निष्क्रिय कर सकते हैं। बेशक आपको const int&int
मोआ

2

हैक की तरह है, लेकिन यह है कि मैं के साथ आया था अगर scoped enums के साथ काम:

enum class OriginalType {
   FOO,  // 0
   BAR   // 1
   END   // 2
};

enum class ExtendOriginalType : std::underlying_type_t<OriginalType> {
   EXTENDED_FOO = static_cast<std::underlying_type_t<OriginalType>>
                                           (OriginalType::END), // 2
   EXTENDED_BAR  // 3
};

और फिर जैसे उपयोग करें:

OriginalType myOriginalType = (OriginalType)ExtendOriginalType::EXTENDED_BAR;

2

यह उत्तर ब्रायन आर। बॉन्डी उत्तर का एक प्रकार है। चूंकि मुझे एक टिप्पणी में अनुरोध किया गया है, मैं इसे उत्तर के रूप में जोड़ रहा हूं। अगर यह वास्तव में लायक है, तो मैं इसके बारे में नहीं बता रहा हूं।

#include <iostream>

class Colors
{
public:
    static Colors RED;
    static Colors GREEN;

    operator int(){ return value; }
    operator int() const{ return value; }

protected:
    Colors(int v) : value{v}{} 

private:
    int value;
};

Colors Colors::RED{1};
Colors Colors::GREEN{2};

class RGB : public Colors
{
public:
    static RGB BLUE;

private:
    RGB(int v) : Colors(v){}
};

RGB RGB::BLUE{10};

int main ()
{
  std::cout << Colors::RED << " " << RGB::RED << std::endl;
}

कोलिरु में रहते हैं


0

असंभव।
लेकिन आप एनम को एक कक्षा में गुमनाम रूप से परिभाषित कर सकते हैं, फिर व्युत्पन्न कक्षाओं में अतिरिक्त एनम स्थिरांक जोड़ सकते हैं।


-2
enum xx {
   ONE = 1,
   TWO,
   xx_Done
};

enum yy {
   THREE = xx_Done,
   FOUR,
};

typedef int myenum;

static map<myenum,string>& mymap() {
   static map<myenum,string> statmap;
   statmap[ONE] = "One";
   statmap[TWO] = "Two";
   statmap[THREE] = "Three";
   statmap[FOUR] = "Four";
   return statmap;
}

उपयोग:

std::string s1 = mamap()[ONE];
std::string s4 = mymap()[FOUR];
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.