একটি সি ++ এনাম ক্লাসের পদ্ধতি থাকতে পারে?


144

আমার দুটি মান সহ একটি এনাম ক্লাস রয়েছে এবং আমি এমন একটি পদ্ধতি তৈরি করতে চাই যা একটি মান পায় এবং অন্যটি প্রদান করে। আমি প্রকারের সুরক্ষাও বজায় রাখতে চাই (এ কারণেই আমি এনামগুলির পরিবর্তে এনাম ক্লাস ব্যবহার করি)।

http://www.cplusplus.com/doc/tutorial/other_data_tyype/ পদ্ধতি সম্পর্কে কিছু উল্লেখ করে না তবে যাইহোক, আমি এই ধারণার মধ্যে ছিলাম যে কোনও ধরণের শ্রেণির পদ্ধতি থাকতে পারে।


4
না, এটা পারে না। এখানে দেখুন ।
juanchopanza

@ অক্টাভিয়ান আমার উত্তরটি নোট করুন এবং আপনার ব্যবহারের ক্ষেত্রে পুনর্বিবেচনা করুন!
πάντα ῥεῖ

@ πάνταῥεῖ আপনি পুরোপুরি ঠিক বলেছেন, আমি এনাম পড়েছি কিন্তু ইউনিয়ন ভেবেছি, মন্তব্যটি মেরে ফেলেছি।
ইউজেন কনস্ট্যান্টিন ডিনকা 23'14

@ অক্টাভিয়ান আপনি কি আদৌ কোনও নির্দিষ্ট ব্যবহারের ক্ষেত্রে জিজ্ঞাসা করছেন, বা আপনি কি কেবল সি ++ 11- র মান সীমাবদ্ধতা enum class/structনিশ্চিত করতে চান?
πάντα ῥεῖ

আমার মনে একটি ব্যবহার ছিল ... এবং এটি ছিল মৌলিক সমস্যা
অষ্টাভিয়ান

উত্তর:


118

না, তারা পারে না।

আমি বুঝতে পারি যে enum classসি ++ 11 এ জোরালোভাবে টাইপ করা এনামগুলির অংশটি বোঝাতে পারে যে আপনার বৈশিষ্ট্যগুলিও enumরয়েছে class, তবে এটি তেমন নয়। আমার শিক্ষিত অনুমান যে কীওয়ার্ডগুলির পছন্দটি স্কপড এনামগুলি পেতে আমরা C ++ 11 এর আগে যে ধরণের ব্যবহার করেছি তা দ্বারা অনুপ্রাণিত হয়েছিল:

class Foo {
public:
  enum {BAR, BAZ};
};

তবে, এটি কেবল বাক্য গঠন। আবার, enum classএকটি হয় না class


88
## সি ++ এ আমাকে জানানো হয়েছিল যে "সি ++ এর লক্ষ্য যতটা সম্ভব বিভ্রান্তিকর এবং বিশেষজ্ঞবান্ধব হতে হবে" । স্পষ্টতই এটি একটি রসিকতা, তবে আপনি ধারণাটি পেয়ে যান :)
স্টেফানো সানফিলিপো

4
unionজন দো কোনও শ্রেণিকে বিবেচনা করবেন তা নয়। তবুও তারা সদস্য কাজ করতে পারে। এবং সদস্য কার্যাদি জন্য ক্লাসগুলি সত্যই বাধ্যতামূলক নয়। ডিজাইনার যেমন valueবা এর thisমতো enum Size { Huge, Mega, Apocalypse; bool operator<(X rhs) const { return *this < rhs; }(এখানেও অনুমতি দেওয়া হয় ;) ব্যবহার করে এটি অন্যান্য ফাংশনগুলির মতোই বোধগম্য হতে পারে।
সেবাস্তিয়ান মাচ

84

"আপনি পারবেন না" উত্তরটি প্রযুক্তিগতভাবে সঠিক হলেও, আমি বিশ্বাস করি যে আপনি নীচের ধারণাটি ব্যবহার করার জন্য যে আচরণটি সন্ধান করছেন তা অর্জন করতে সক্ষম হতে পারেন:

আমি ধারণা করি আপনি কিছু লিখতে চান:

Fruit f = Fruit::Strawberry;
f.IsYellow();

এবং আপনি আশা করেছিলেন যে কোডটি দেখতে কিছুটা এমন দেখাচ্ছে:

enum class Fruit : uint8_t
{
  Apple, 
  Pear,
  Banana,
  Strawberry,

  bool IsYellow() { return this == Banana; }
};

...

তবে অবশ্যই এটি কাজ করে না, কারণ এনামগুলিতে পদ্ধতি থাকতে পারে না (এবং 'এটি' উপরের প্রসঙ্গে কোনও অর্থ দেয় না)

তবে, আপনি যদি একটি নন-ক্লাস এনাম এবং একটি একক সদস্যের ভেরিয়েবলযুক্ত একটি সাধারণ শ্রেণীর ধারণা ব্যবহার করেন যা এই ধরণের মান ধারণ করে তবে আপনি যে সিনট্যাক্স / আচরণ / টাইপ সুরক্ষাটি চান তার চূড়ান্তভাবে পেতে পারেন। অর্থাৎ,

class Fruit
{
public:
  enum Value : uint8_t
  {
    Apple,
    Pear,
    Banana,
    Strawberry
  };

  Fruit() = default;
  constexpr Fruit(Value aFruit) : value(aFruit) { }

#if Enable switch(fruit) use case:
  operator Value() const { return value; }  // Allow switch and comparisons.
                                            // note: Putting constexpr here causes
                                            // clang to stop warning on incomplete
                                            // case handling.
  explicit operator bool() = delete;        // Prevent usage: if(fruit)
#else
  constexpr bool operator==(Fruit a) const { return value == a.value; }
  constexpr bool operator!=(Fruit a) const { return value != a.value; }
#endif

  constexpr bool IsYellow() const { return value == Banana; }

private:
  Value value;
};

এখন আপনি লিখতে পারেন:

Fruit f = Fruit::Strawberry;
f.IsYellow();

এবং সংকলক এই জাতীয় জিনিসগুলি প্রতিরোধ করবে:

Fruit f = 1;  // Compile time error.

আপনি সহজেই এমন পদ্ধতি যুক্ত করতে পারেন:

Fruit f("Apple");

এবং

f.ToString();

সমর্থিত হতে পারে।


1
ইসয়েলও (), অপারেটর ==,! = কনস্টেক্সপ্র হিসাবে চিহ্নিত করা উচিত নয়?
জারেক সি

আমি "ত্রুটি পেয়েছি: টোকেন" সুইচ "" এর আগে বাইনারি অপারেটর মিস করছি
পেড্রো 77

18

শিরোনামের পরিবর্তে প্রশ্নের বর্ণনায় মনোনিবেশ করা একটি সম্ভাব্য উত্তর

struct LowLevelMouseEvent {
    enum Enum {
        mouse_event_uninitialized = -2000000000, // generate crash if try to use it uninitialized.
        mouse_event_unknown = 0,
        mouse_event_unimplemented,
        mouse_event_unnecessary,
        mouse_event_move,
        mouse_event_left_down,
        mouse_event_left_up,
        mouse_event_right_down,
        mouse_event_right_up,
        mouse_event_middle_down,
        mouse_event_middle_up,
        mouse_event_wheel
    };
    static const char* ToStr (const type::LowLevelMouseEvent::Enum& event)
    {
        switch (event) {
            case mouse_event_unknown:         return "unknown";
            case mouse_event_unimplemented:   return "unimplemented";
            case mouse_event_unnecessary:     return "unnecessary";
            case mouse_event_move:            return "move";
            case mouse_event_left_down:       return "left down";
            case mouse_event_left_up:         return "left up";
            case mouse_event_right_down:      return "right down";
            case mouse_event_right_up:        return "right up";
            case mouse_event_middle_down:     return "middle down";
            case mouse_event_middle_up:       return "middle up";
            case mouse_event_wheel:           return "wheel";
            default:
                Assert (false);
                break;
        }
        return "";
    }
};

4

অন্য উত্তরে যেমন উল্লেখ করা হয়েছে , না। এমনকি enum classকোনও ক্লাস নয়।


সাধারণত প্রয়োজন একটি জন্য পদ্ধতি আছে enumকারণ থেকে ফলাফল যে এটি একটি নয় নিয়মিত (ঠিক বৃদ্ধিশীল) enum, তবে মানগুলির, bitwise সংজ্ঞা ধরনের ছদ্মবেশী বা অন্যান্য বিট-গাণিতিক অপারেশন প্রয়োজন হবে:

enum class Flags : unsigned char {
    Flag1 = 0x01 , // Bit #0
    Flag2 = 0x02 , // Bit #1
    Flag3 = 0x04 , // Bit #3
    // aso ...
}

// Sets both lower bits
unsigned char flags = (unsigned char)(Flags::Flag1 | Flags::Flag2);

// Set Flag3
flags |= Flags::Flag3;

// Reset Flag2
flags &= ~Flags::Flag2;

স্পষ্টতই একজন বিটগুলির একক / গোষ্ঠী পুনরায় সেট / সেট করতে প্রয়োজনীয় ক্রিয়াকলাপগুলি আবদ্ধ করার কথা ভাবেন, যেমন বিট মাস্ক মান বা এমনকি বিট সূচক চালিত ক্রিয়াকলাপগুলি এই জাতীয় 'পতাকা' সেটাকে ম্যানিপুলেশনের জন্য কার্যকর হবে।

দ্য struct/ class নির্দিষ্টকরণ কেবল অ্যাক্সেসের জন্য এনাম মানগুলির আরও ভাল স্কোপিং সমর্থন করে। বেশিও না, কমও না!

সীমাবদ্ধতা থেকে বেরিয়ে আসার উপায়গুলি আপনি এনাম (ক্লাস) এর পদ্ধতিগুলি ঘোষণা করতে পারবেন না , হয় std::bitset(মোড়কের ক্লাস), বা বিটফিল্ড ব্যবহার করার জন্যunion

unionগুলি এবং এই জাতীয় বিটফিল্ড ইউনিয়নগুলির পদ্ধতি থাকতে পারে ( বিধিনিষেধের জন্য এখানে দেখুন !)

আমার একটি নমুনা রয়েছে, কীভাবে বিট মাস্কের মানগুলি (যেমন উপরে দেখানো হয়েছে) তাদের সম্পর্কিত বিট সূচকগুলিতে রূপান্তর করতে হবে, এটি std::bitsetএখানে ব্যবহার করা যেতে পারে : BitIndexConverter
hpp আলগোরিদিম।


36
এনাম সংঘর্ষের জন্য ওয়ারেন্ট পদ্ধতিগুলি যেমন: টু স্ট্রিং () এবং স্ট্রিং () থেকে আরও ব্যবহারের ক্ষেত্রে রয়েছে warrant প্রতিটি (এমনকি এটি নয়) আধুনিক প্রধান ভাষায় এটি রয়েছে (যেমন সি #, জাভা, সুইফ্ট), কেবল সি ++ নয়।
মাইক লিসচে

1
আসুন পরের বারের মতো ইউনিফাইড কল সিনট্যাক্সের জন্য আশা করি ... ওপেন-std.org/jtc1/sc22/wg21/docs/papers/2014/n4165.pdf
sdgfsdh

4

আপনার কোডটি নতুন করে লিখতে না পেরে একটি এনামকে ক্লাসে রিফ্যাক্টর করার জন্য একটি সুসংগত সামর্থ্য (§) রয়েছে যার অর্থ আপনি খুব বেশি সম্পাদনা না করে যা করতে বলছিলেন তা কার্যকরভাবে করতে পারেন

(§) এলিমেন্ট ডাব্লু একটি মন্তব্যে উল্লেখ করেছে যে, টাইপ_ট্রেটস নির্ভরশীল কোডটি কাজ করবে না, উদাহরণস্বরূপ, কেউ অটো ব্যবহার করতে পারে না ইত্যাদি stuff এবং সি ++ টি বর্জন করা সর্বদা ভুল

enum structএবং enum classবিশেষ উল্লেখ তাই এই অংশ নয় scoping চলেছেন।

আপনার মূল এনাম উদাহরণস্বরূপ 'পোষা প্রাণী' (এটি কেবল উদাহরণ হিসাবে!)।

enum pet { 
    fish, cat, dog, bird, rabbit, other 
};

(1) আপনি এটিকে উদাহরণস্বরূপ পেটইনামে পরিবর্তন করুন (যাতে এটি আপনার বিদ্যমান কোড থেকে আড়াল করা যায়)।

enum petEnum { 
    fish, cat, dog, bird, rabbit, other 
};

(২) আপনি এর নীচে একটি নতুন শ্রেণির ঘোষণা যুক্ত করুন (মূল এনামের সাথে নামকরণ)

class pet {
    private:
        petEnum value;
        pet() {}

    public:
        pet(const petEnum& v) : value{v} {} //not explicit here.
        operator petEnum() const { return value; }
        pet& operator=(petEnum v) { value = v; return *this;}
        bool operator==(const petEnum v) const { return value == v; }
        bool operator!=(const petEnum v) const { return value != v; }
 //     operator std::string() const;

};

(3) আপনি এখন আপনার পোষা প্রাণীর ক্লাসে আপনার পছন্দ মতো ক্লাসের পদ্ধতিগুলি যুক্ত করতে পারেন। যেমন। একটি স্ট্রিং অপারেটর

    pet::operator std::string() const {
        switch (value) {
            case fish: return "fish";
            case cat:  return "cat";
            case dog:  return "dog";
            case bird: return "bird";
            case rabbit: return "rabbit";
            case other: return "Wow. How exotic of you!";
        }
    }

এখন আপনি যেমন স্টাড :: কোট ব্যবহার করতে পারেন ...

int main() {
    pet myPet = rabbit;
    if(myPet != fish) {
        cout << "No splashing! ";
    }
    std::cout << "I have a " << std::string(myPet) << std::endl;
    return 0;
}

1
এটা না সম্পূর্ণরূপে সুসংগত: আপনি টাইপ সিদ্ধান্তগ্রহণ যে কোন ধরণের যেখানে এটি একটি পেতে আশা করা হচ্ছে সঙ্গে enum মান ব্যবহার pettypename / উদাহরণস্বরূপ, এটি টেমপ্লেট হও, autoঅথবা decltype, এই বিরতি, যেমন আপনি যদি একটি পেতে petEnumপরিবর্তে।
এলিমেন্টব্লু

0

এটি আপনার সমস্ত চাহিদা পূরণ করতে পারে না, তবে সদস্যবিহীন অপারেটরগুলির সাথে আপনি এখনও অনেক মজা করতে পারেন। উদাহরণ স্বরূপ:

#include <iostream>

enum class security_level
{
    none, low, medium, high
};

static bool operator!(security_level s) { return s == security_level::none; }

static security_level& operator++(security_level& s)
{
    switch(s)
    {
        case security_level::none: s = security_level::low; break;
        case security_level::low: s = security_level::medium; break;
        case security_level::medium: s = security_level::high; break;
        case security_level::high: break;
    }
    return s;
}

static std::ostream & operator<<(std::ostream &o, security_level s)
{
    switch(s)
    {
        case security_level::none: return o << "none";
        case security_level::low: return o << "low";
        case security_level::medium: return o << "medium";
        case security_level::high: return o << "high";
    }
}

এটি কোড পছন্দ করে

security_level l = security_level::none;   
if(!!l) { std::cout << "has a security level: " << l << std::endl; } // not reached
++++l;
if(!!l) { std::cout << "has a security level: " << l << std::endl; } // reached: "medium"
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.