मैंने कुछ लोगों को उनकी प्रकार की सुरक्षा के कारण C ++ में enum classes का उपयोग करने की सलाह देते हुए सुना ।
लेकिन असल में उसका क्या अर्थ है?
मैंने कुछ लोगों को उनकी प्रकार की सुरक्षा के कारण C ++ में enum classes का उपयोग करने की सलाह देते हुए सुना ।
लेकिन असल में उसका क्या अर्थ है?
जवाबों:
C ++ के दो प्रकार हैं enum
:
enum class
esenum
sयहाँ कुछ उदाहरण दिए गए हैं कि उन्हें कैसे घोषित किया जाए:
enum class Color { red, green, blue }; // enum class
enum Animal { dog, cat, bird, human }; // plain enum
दो में क्या अंतर है?
enum class
es - एन्यूमरेटर नाम एनम के लिए स्थानीय हैं और उनके मान अन्य प्रकार (जैसे या किसी अन्य ) में रूपांतरित नहीं होते हैंenum
int
प्लेन enum
s - जहां एन्यूमरेटर नाम एक ही दायरे में हैं क्योंकि एनम और उनके मानों को संक्षेप में पूर्णांकों और अन्य प्रकारों में बदल दिया जाता है
उदाहरण:
enum Color { red, green, blue }; // plain enum
enum Card { red_card, green_card, yellow_card }; // another plain enum
enum class Animal { dog, deer, cat, bird, human }; // enum class
enum class Mammal { kangaroo, deer, human }; // another enum class
void fun() {
// examples of bad use of plain enums:
Color color = Color::red;
Card card = Card::green_card;
int num = color; // no problem
if (color == Card::red_card) // no problem (bad)
cout << "bad" << endl;
if (card == Color::green) // no problem (bad)
cout << "bad" << endl;
// examples of good use of enum classes (safe)
Animal a = Animal::deer;
Mammal m = Mammal::deer;
int num2 = a; // error
if (m == a) // error (good)
cout << "bad" << endl;
if (a == Mammal::deer) // error (good)
cout << "bad" << endl;
}
enum class
एस को प्राथमिकता दी जानी चाहिए क्योंकि वे कम आश्चर्य का कारण बनते हैं जो संभवतः कीड़े के लिए नेतृत्व कर सकते हैं।
A
राज्य के साथ एक वर्ग है, और मैं enum class State { online, offline };
कक्षा के एक बच्चे के रूप में बनाता A
हूं, तो मैं इसके बजाय state == online
चेक करना चाहूंगा ... क्या यह संभव है? A
state == State::online
enum class
इसे खत्म करने का आधा औचित्य था।
Color color = Color::red
।
if (color == Card::red_card)
लाइन तक नहीं होता है, टिप्पणी की तुलना में 4 लाइनों के बाद (जो मुझे अब ब्लॉक के पहले छमाही पर लागू होता है।) ब्लॉक की 2 लाइनें खराब उदाहरण देती हैं। पहली 3 लाइनें कोई समस्या नहीं हैं। "पूरे ब्लॉक क्यों सादे enums बुरा है" मुझे फेंक दिया क्योंकि मुझे लगा कि आप का मतलब है कि कुछ भी उन लोगों के साथ गलत था। मैं अब देख रहा हूं, यह सिर्फ एक सेट-अप है। किसी भी मामले में, प्रतिक्रिया के लिए धन्यवाद।
से Bjarne Stroustrup की सी ++ 11 अकसर किये गए सवाल :
enum class
तों ( "नया enums", "मजबूत enums") पता परंपरागत सी ++ enumerations के साथ तीन समस्याओं:
- पारंपरिक रूप से गुप्त रूप से इंट में परिवर्तित हो जाते हैं, जिससे त्रुटियां तब होती हैं जब कोई एक पूर्णांक के रूप में कार्य करना नहीं चाहता है।
- पारंपरिक एनम अपने संयुक्ताक्षरों को आसपास के दायरे में निर्यात करते हैं, जिससे नाम की गड़बड़ी होती है।
- अंतर्निहित प्रकार को
enum
निर्दिष्ट नहीं किया जा सकता है, जिससे भ्रम, संगतता समस्याएं पैदा होती हैं, और आगे की घोषणा को असंभव बना देता है।नई दुश्मनी "एनम क्लास" है क्योंकि वे पारंपरिक एनुमरेशंस (नाम मूल्यों) के पहलुओं को वर्गों के पहलुओं (स्कोप्ड सदस्यों और रूपांतरणों की अनुपस्थिति) के साथ जोड़ती हैं।
इसलिए, जैसा कि अन्य उपयोगकर्ताओं द्वारा कहा गया है, "मजबूत एनम" कोड को सुरक्षित बना देगा।
"क्लासिक" का अंतर्निहित प्रकार enum
एक पूर्णांक प्रकार होगा जो सभी के मूल्यों को फिट करने के लिए पर्याप्त है enum
; यह आमतौर पर एक है int
। इसके अलावा प्रत्येक प्रगणित प्रकार संगत होगाchar
एक हस्ताक्षरित / अहस्ताक्षरित पूर्णांक प्रकार ।
यह एक विस्तृत विवरण है कि एक enum
अंतर्निहित प्रकार क्या होना चाहिए, इसलिए प्रत्येक कंपाइलर क्लासिक के अंतर्निहित प्रकार के बारे में अपने दम पर निर्णय लेगाenum
और कभी-कभी परिणाम आश्चर्यजनक हो सकता है।
उदाहरण के लिए, मैंने कई बार इस तरह का एक कोड देखा है:
enum E_MY_FAVOURITE_FRUITS
{
E_APPLE = 0x01,
E_WATERMELON = 0x02,
E_COCONUT = 0x04,
E_STRAWBERRY = 0x08,
E_CHERRY = 0x10,
E_PINEAPPLE = 0x20,
E_BANANA = 0x40,
E_MANGO = 0x80,
E_MY_FAVOURITE_FRUITS_FORCE8 = 0xFF // 'Force' 8bits, how can you tell?
};
ऊपर दिए गए कोड में, कुछ भोले-भाले कोडर सोच रहे हैं कि कंपाइलर E_MY_FAVOURITE_FRUITS
मानों को एक अहस्ताक्षरित 8 बिट प्रकार में संग्रहीत करेगा ... लेकिन इसके बारे में कोई वारंटी नहीं है: कंपाइलर उन सभी में से किसी एक प्रकार का चयन unsigned char
या int
या कर सकता है short
, जो किसी भी प्रकार के बड़े हैं। में देखे गए मूल्य enum
। फ़ील्ड जोड़ना E_MY_FAVOURITE_FRUITS_FORCE8
एक बोझ है और यह कंपाइलर को अंतर्निहित प्रकार के बारे में किसी भी तरह का चुनाव करने के लिए मजबूर नहीं करता है enum
।
यदि कोड का कोई टुकड़ा है जो प्रकार के आकार और / या पर भरोसा करता है जो कि E_MY_FAVOURITE_FRUITS
कुछ चौड़ाई का होगा (जैसे: क्रमांकन दिनचर्या) यह कोड संकलक के विचारों के आधार पर कुछ अजीब तरीकों से व्यवहार कर सकता है।
और मामले को बदतर बनाने के लिए, अगर कुछ वर्कमेट लापरवाही से हमारे लिए एक नया मूल्य जोड़ता है enum
:
E_DEVIL_FRUIT = 0x100, // New fruit, with value greater than 8bits
संकलक इसके बारे में शिकायत नहीं करता है! यह बस के सभी मूल्यों को फिट करने के प्रकार का enum
अनुमान लगाता है (यह मानते हुए कि संकलक संभव छोटे प्रकार का उपयोग कर रहे हैं, जो एक धारणा है कि हम नहीं कर सकते हैं)। इस सरल और लापरवाह इसके अलावाenum
संबंधित कोड को तोड़ सकता है।
चूंकि C ++ 11 के लिए अंतर्निहित प्रकार enum
और enum class
(धन्यवाद rdb ) को निर्दिष्ट करना संभव है, इसलिए इस मुद्दे को बड़े करीने से संबोधित किया गया है:
enum class E_MY_FAVOURITE_FRUITS : unsigned char
{
E_APPLE = 0x01,
E_WATERMELON = 0x02,
E_COCONUT = 0x04,
E_STRAWBERRY = 0x08,
E_CHERRY = 0x10,
E_PINEAPPLE = 0x20,
E_BANANA = 0x40,
E_MANGO = 0x80,
E_DEVIL_FRUIT = 0x100, // Warning!: constant value truncated
};
अंतर्निहित प्रकार को निर्दिष्ट करना यदि किसी क्षेत्र में इस प्रकार की सीमा से बाहर की अभिव्यक्ति है तो संकलक अंतर्निहित प्रकार को बदलने के बजाय शिकायत करेगा।
मुझे लगता है कि यह एक अच्छा सुरक्षा सुधार है।
तो एनम वर्ग को सादे एनम पर क्यों पसंद किया जाता है? , अगर हम स्कोप्ड ( enum class
) और अनकैप्ड ( enum
) एनम के लिए अंतर्निहित प्रकार का चयन कर सकते हैं तो और क्या enum class
बेहतर विकल्प है ?:
int
।सामान्य एनमों पर एनम वर्ग का उपयोग करने का मूल लाभ यह है कि आपके पास 2 अलग-अलग एनमों के लिए समान एनम चर हो सकते हैं और फिर भी उन्हें हल कर सकते हैं (जिसका उल्लेख प्रकार सुरक्षित है ओपी द्वारा )
उदाहरण के लिए:
enum class Color1 { red, green, blue }; //this will compile
enum class Color2 { red, green, blue };
enum Color1 { red, green, blue }; //this will not compile
enum Color2 { red, green, blue };
मूल एनम के लिए, कंपाइलर यह भेद नहीं red
कर पाएगा कि वह कथन के अनुसार टाइप Color1
कर रहा है या नहीं Color2
।
enum Color1 { red, green, blue };
enum Color2 { red, green, blue };
int x = red; //Compile time error(which red are you refering to??)
enum { COLOR1_RED, COLOR1_GREE, COLOR1_BLUE }
नाम स्थान के मुद्दों को आसानी से लिखेंगे । नाम स्थान तर्क तीन में से एक है जिसका उल्लेख यहां किया गया है जो मैं बिल्कुल नहीं खरीदता हूं।
enum Color1 { COLOR1_RED, COLOR1_GREEN, COLOR1_BLUE }
Enum वर्ग के लिए तुलनीय है enum class Color1 { RED, GREEN, BLUE }
:। एक्सेस करना समान है: COLOR1_RED
बनाम Color1::RED
, लेकिन एनम संस्करण के लिए आपको प्रत्येक मूल्य में "COLOR1" टाइप करना होगा, जो टाइपोस के लिए अधिक जगह देता है, जो एनम वर्ग के नाम स्थान के व्यवहार से बचता है।
enum Color1
, जो एक संकलक नहीं पकड़ सकता है क्योंकि यह संभवतः अभी भी एक 'मान्य' नाम होगा। यदि मैं लिखता हूं RED
, GREEN
और एक एनम वर्ग का उपयोग कर रहा हूं , तो इससे हल नहीं हो सकता enum Banana
क्योंकि इसके लिए आपको Color1::RED
मूल्य (नाम स्थान तर्क) तक पहुंचने के लिए निर्दिष्ट करना होगा । उपयोग करने के लिए अभी भी अच्छे समय हैं enum
, लेकिन कैन के नाम स्थान का व्यवहार enum class
अक्सर बहुत फायदेमंद हो सकता है।
एन्यूमरेशन का उपयोग पूर्णांक मानों के एक समूह का प्रतिनिधित्व करने के लिए किया जाता है।
यह निर्दिष्ट class
करने के बाद enum
कि एन्यूमरेशन दृढ़ता से टाइप किया गया है और उसके एन्यूमरेटर्स को स्कोप किया गया है। इस तरह enum
कक्षाएं स्थिरांक के आकस्मिक दुरुपयोग को रोकती हैं।
उदाहरण के लिए:
enum class Animal{Dog, Cat, Tiger};
enum class Pets{Dog, Parrot};
यहां हम पशु और पालतू जानवरों के मूल्यों को नहीं मिला सकते हैं।
Animal a = Dog; // Error: which DOG?
Animal a = Pets::Dog // Pets::Dog is not an Animal
C ++ 11 FAQ में नीचे दिए गए बिंदुओं का उल्लेख है:
पारंपरिक रूप से गुप्त रूप से इंट में परिवर्तित हो जाते हैं, जिससे त्रुटियां तब होती हैं जब कोई एक पूर्णांक के रूप में कार्य करना नहीं चाहता है।
enum color
{
Red,
Green,
Yellow
};
enum class NewColor
{
Red_1,
Green_1,
Yellow_1
};
int main()
{
//! Implicit conversion is possible
int i = Red;
//! Need enum class name followed by access specifier. Ex: NewColor::Red_1
int j = Red_1; // error C2065: 'Red_1': undeclared identifier
//! Implicit converison is not possible. Solution Ex: int k = (int)NewColor::Red_1;
int k = NewColor::Red_1; // error C2440: 'initializing': cannot convert from 'NewColor' to 'int'
return 0;
}
पारंपरिक एनम अपने संयुक्ताक्षरों को आसपास के दायरे में निर्यात करते हैं, जिससे नाम की गड़बड़ी होती है।
// Header.h
enum vehicle
{
Car,
Bus,
Bike,
Autorickshow
};
enum FourWheeler
{
Car, // error C2365: 'Car': redefinition; previous definition was 'enumerator'
SmallBus
};
enum class Editor
{
vim,
eclipes,
VisualStudio
};
enum class CppEditor
{
eclipes, // No error of redefinitions
VisualStudio, // No error of redefinitions
QtCreator
};
एक प्रकार का एनम निर्दिष्ट नहीं किया जा सकता है, जिससे भ्रम, अनुकूलता की समस्याएं होती हैं, और आगे की घोषणा को असंभव बना देता है।
// Header1.h
#include <iostream>
using namespace std;
enum class Port : unsigned char; // Forward declare
class MyClass
{
public:
void PrintPort(enum class Port p);
};
void MyClass::PrintPort(enum class Port p)
{
cout << (int)p << endl;
}
।
// Header.h
enum class Port : unsigned char // Declare enum type explicitly
{
PORT_1 = 0x01,
PORT_2 = 0x02,
PORT_3 = 0x04
};
।
// Source.cpp
#include "Header1.h"
#include "Header.h"
using namespace std;
int main()
{
MyClass m;
m.PrintPort(Port::PORT_1);
return 0;
}
यह ध्यान देने योग्य है, इन अन्य उत्तरों के शीर्ष पर, कि C ++ 20 में से एक समस्या enum class
है: वाचालता। एक काल्पनिक कल्पना enum class
, Color
।
void foo(Color c)
switch (c) {
case Color::Red: ...;
case Color::Green: ...;
case Color::Blue: ...;
// etc
}
}
यह सादे enum
भिन्नता की तुलना में क्रिया है , जहां नाम वैश्विक दायरे में हैं और इसलिए इसके साथ उपसर्ग करने की आवश्यकता नहीं है Color::
।
हालाँकि, C ++ 20 में हम using enum
समस्या को हल करने के लिए, enum में सभी नामों को वर्तमान दायरे में लाने के लिए उपयोग कर सकते हैं ।
void foo(Color c)
using enum Color;
switch (c) {
case Red: ...;
case Green: ...;
case Blue: ...;
// etc
}
}
तो अब, उपयोग नहीं करने का कोई कारण नहीं है enum class
।
क्योंकि, जैसा कि अन्य उत्तरों में कहा गया है, वर्ग ईनम गुप्त रूप से इंट / बूल के लिए परिवर्तनीय नहीं हैं, यह बग्गी कोड से बचने में भी मदद करता है जैसे:
enum MyEnum {
Value1,
Value2,
};
...
if (var == Value1 || Value2) // Should be "var == Value2" no error/warning
एक बात जिसका स्पष्ट उल्लेख नहीं किया गया है - गुंजाइश सुविधा आपको एक एनुम और क्लास विधि के लिए एक ही नाम रखने का विकल्प देती है। उदाहरण के लिए:
class Test
{
public:
// these call ProcessCommand() internally
void TakeSnapshot();
void RestoreSnapshot();
private:
enum class Command // wouldn't be possible without 'class'
{
TakeSnapshot,
RestoreSnapshot
};
void ProcessCommand(Command cmd); // signal the other thread or whatever
};