আমি শুনেছি কয়েকজন লোক তাদের ধরণের সুরক্ষার কারণে সি ++ এ এনাম ক্লাস ব্যবহার করার পরামর্শ দিচ্ছে ।
তবে এর অর্থ কী?
আমি শুনেছি কয়েকজন লোক তাদের ধরণের সুরক্ষার কারণে সি ++ এ এনাম ক্লাস ব্যবহার করার পরামর্শ দিচ্ছে ।
তবে এর অর্থ কী?
উত্তর:
সি ++ এর মধ্যে দুই ধরণের রয়েছে enum
:
enum class
স্প্যানিশ ভাষায়enum
এসএগুলি কীভাবে ঘোষণা করবেন তা এখানে বেশ কয়েকটি উদাহরণ রয়েছে:
enum class Color { red, green, blue }; // enum class
enum Animal { dog, cat, bird, human }; // plain enum
দুজনের মধ্যে পার্থক্য কী?
enum class
এস - গণনার নাম এনামের কাছে স্থানীয় এবং তাদের মানগুলি স্পষ্টভাবে অন্য ধরণের রূপান্তরিত করে না (অন্য কোনও enum
বা এর মতো int
)
সমভূমি enum
- যেখানে গণকের নাম এনামের মতো একই স্কোপে থাকে এবং তাদের মানগুলি স্পষ্টভাবে পূর্ণসংখ্যা এবং অন্যান্য ধরণের রূপান্তর করে
উদাহরণ:
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 লাইন কোনও সমস্যা নয়। "পুরো ব্লকটি কেন সরল এনামগুলি খারাপ" আমাকে নিক্ষেপ করেছিল কারণ আমি ভেবেছিলাম যে আপনিও বোঝাতে চেয়েছিলেন যে তাদের মধ্যেও কিছু ভুল ছিল। আমি এখন দেখছি, এটি একটি সেট আপ মাত্র। যাই হোক না কেন, প্রতিক্রিয়া জন্য ধন্যবাদ।
থেকে বিয়ারনে স্ট্রোভস্ট্রুপের এর সি ++ 11 প্রায়শই জিজ্ঞাসিত প্রশ্নাবলী :
enum class
স্প্যানিশ ভাষায় ( "নতুন enums", "শক্তিশালী enums") ঠিকানা ঐতিহ্যগত সি ++ enumerations সঙ্গে তিন সমস্যা মন্তব্য:
- প্রচলিত এনামগুলি সুস্পষ্টভাবে ইন্টে রূপান্তর করে, ত্রুটি সৃষ্টি করে যখন কেউ কোনও সংখ্যার পূর্ণসংখ্যা হিসাবে কাজ করতে চায় না।
- প্রচলিত এনামগুলি তাদের সংখ্যককে আশেপাশের স্কোপে রফতানি করে যার ফলে নাম সংঘর্ষ হয়।
- এর অন্তর্নিহিত ধরণ
enum
নির্দিষ্ট করা যায় না, বিভ্রান্তি সৃষ্টি করে, সামঞ্জস্যের সমস্যা সৃষ্টি করে এবং সামনে ঘোষণা অসম্ভব করে তোলে।নতুন এনামগুলি "এনাম ক্লাস", কারণ তারা ক্লাসের দিকগুলি (স্কোপড সদস্য এবং রূপান্তরগুলির অনুপস্থিতি) এর সাথে traditionalতিহ্যবাহী গণনাগুলির (নামগুলির মানগুলি) একত্রিত করে।
সুতরাং, অন্যান্য ব্যবহারকারীদের দ্বারা উল্লিখিত হিসাবে, "শক্তিশালী enums" কোডটি নিরাপদ করে তুলবে।
"ক্লাসিক" এর অন্তর্নিহিত প্রকারটি 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
একটি স্বাক্ষরবিহীন 8bit ধরনের মধ্যে মান ... কিন্তু এটি সম্পর্কে কোন পাটা আছে: কম্পাইলার চয়ন করতে পারেন 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
সূক্ষ্মতা সম্পর্কিত সম্পর্কিত কোডটিতে এই সহজ এবং অযত্ন সংযোজন ।
যেহেতু সি ++ 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
নীচের বিবৃতিতে hte তে পৃথক করতে পারবেন না ।
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 বর্গ ব্যবহার না করে এটি সমাধান না করতে পারেন enum Banana
, কারণ এটি আপনাকে তা নির্দিষ্ট প্রয়োজন Color1::RED
মান (নামস্থান যুক্তি) অ্যাক্সেস করার জন্য। এখনও ব্যবহারের জন্য ভাল সময় রয়েছে enum
, তবে একটির নামের স্থানটি enum class
প্রায়শই খুব উপকারী হতে পারে।
অঙ্কগুলি পূর্ণসংখ্যার মানগুলির সেটকে উপস্থাপন করতে ব্যবহৃত হয়।
class
শব্দ পর enum
নির্দিষ্ট করে শুমার শক্তিশালী ভাবে টাইপ করা হয় এবং তার তথ্যসংগ্রহকারী scoped হয়। এইভাবে 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
সি ++ ১১ টি প্রায়শই জিজ্ঞাসিত প্রশ্নাগুলি নীচে উল্লেখ করেছেন:
প্রচলিত এনামগুলি সুস্পষ্টভাবে ইন্টে রূপান্তর করে, ত্রুটি সৃষ্টি করে যখন কেউ কোনও সংখ্যার পূর্ণসংখ্যা হিসাবে কাজ করতে চায় না।
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;
}
এই অন্যান্য উত্তরের উপরে, এটি লক্ষণীয় যে সি ++ 20 এর যে কোনও একটি সমস্যা সমাধান করে enum class
: ভার্বোসটি। একটি প্রকল্পিত কল্পী enum class
, Color
।
void foo(Color c)
switch (c) {
case Color::Red: ...;
case Color::Green: ...;
case Color::Blue: ...;
// etc
}
}
এটি সরল enum
প্রকরণের সাথে তুলনা করে ভার্বোজ , যেখানে নামগুলি বিশ্বব্যাপী সুযোগে রয়েছে এবং তাই এর সাথে উপসর্গের প্রয়োজন হবে না Color::
।
যাইহোক, সি ++ 20 এ আমরা using 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
};