Khai báo một enum trong một lớp


150

Trong đoạn mã sau, Colorenum được khai báo trong Carlớp để giới hạn phạm vi của enum và cố gắng không "làm ô nhiễm" không gian tên toàn cục.

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;

};

(1) Đây có phải là một cách tốt để giới hạn phạm vi của Colorenum? Hoặc, tôi nên khai báo nó bên ngoài Carlớp, nhưng có thể trong không gian tên hoặc cấu trúc của chính nó? Tôi vừa xem qua bài viết này hôm nay, trong đó ủng hộ phần sau và thảo luận về một số điểm hay về enums: http://gamesfromwithin.com/stool-c-tricks-2-better-enums .

(2) Trong ví dụ này, khi làm việc trong lớp, tốt nhất là viết mã enum như Car::Color, hoặc chỉ là Colorđủ? (Tôi cho rằng cái trước là tốt hơn, chỉ trong trường hợp có một Colorenum khác được khai báo trong không gian tên toàn cầu. Bằng cách đó, ít nhất, chúng tôi rõ ràng về enum mà chúng tôi đang đề cập.)

Câu trả lời:


85
  1. Nếu Colorcó một cái gì đó chỉ dành riêng cho Cars thì đó là cách bạn sẽ giới hạn phạm vi của nó. Nếu bạn sắp có một Colorenum khác mà các lớp khác sử dụng thì bạn cũng có thể làm cho nó trở nên toàn cầu (hoặc ít nhất là bên ngoài Car).

  2. Nó không có Gì Thay đổi. Nếu có một cái toàn cầu thì cái địa phương vẫn được sử dụng vì nó gần với phạm vi hiện tại. Lưu ý rằng nếu bạn xác định các hàm đó bên ngoài định nghĩa lớp thì bạn sẽ cần chỉ định rõ ràng Car::Colortrong giao diện của hàm.


12
2. Có và không. Car::Color getColor()nhưng void Car::setColor(Color c)bởi vì trong setColorchúng tôi đã có specifier.
Matthieu M.


66

Tôi thích cách tiếp cận sau (mã dưới đây). Nó giải quyết vấn đề "ô nhiễm không gian tên", nhưng nó cũng an toàn hơn nhiều (bạn không thể chỉ định và thậm chí so sánh hai cách liệt kê khác nhau hoặc liệt kê của bạn với bất kỳ loại tích hợp nào khác, v.v.).

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

Sử dụng:

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

Tôi tạo macro để tạo điều kiện sử dụng:

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

Sử dụng:

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

Một số tài liệu tham khảo:

  1. Herb Sutter, Jum Hyslop, Tạp chí người dùng C / C ++, 22 (5), tháng 5 năm 2004
  2. Herb Sutter, David E. Miller, Bjarne Stroustrup Gõ mạnh Enums (phiên bản 3), tháng 7 năm 2007

Tôi thích điều này. Nó cũng buộc enum phải được khởi tạo với một giá trị hợp lệ. Tôi nghĩ rằng một toán tử gán và hàm tạo sao chép sẽ hữu ích. Ngoài ra t_ nên riêng tư. Các macro tôi có thể làm mà không cần.
jmucchiello

Tôi cũng thích điều này Cảm ơn các tài liệu tham khảo.
anio

1
Bạn nói: "nó cũng an toàn hơn nhiều (bạn không thể gán và thậm chí so sánh hai cách liệt kê khác nhau ..." . Tại sao bạn nghĩ đó là một tính năng tốt? Tôi nghĩ if(c2 == Color::Red )là hợp lý và phải biên dịch, nhưng trong ví dụ của bạn cũng không. Lập luận tương tự cho bài tập cũng được!
Nawaz

3
@Nawaz c2thuộc loại khác ( Color2), vậy tại sao bạn nghĩ c2 == Color::Redvà bài tập nên biên dịch? Nếu Color::Redlà 1, và Color2::Redlà 2 thì sao? Nên Color::Red == Color2::Redđánh giá truehay false? Nếu bạn kết hợp các liệt kê không an toàn, bạn sẽ có một khoảng thời gian tồi tệ.
Victor K

2
Tại sao không phải là loại t_; riêng tư?
Zingam

7

Nói chung, tôi luôn đặt enum của tôi trong a struct. Tôi đã thấy một số hướng dẫn bao gồm "tiền tố".

enum Color
{
  Clr_Red,
  Clr_Yellow,
  Clr_Blue,
};

Luôn nghĩ rằng điều này trông giống như Chướng dẫn hơn là hướng dẫn C++(vì một vì viết tắt và cũng vì các không gian tên trong C++).

Vì vậy, để giới hạn phạm vi chúng ta có hai lựa chọn thay thế:

  • không gian tên
  • cấu trúc / lớp

Cá nhân tôi có xu hướng sử dụng structvì nó có thể được sử dụng làm tham số cho lập trình mẫu trong khi không gian tên không thể được thao tác.

Ví dụ về thao tác bao gồm:

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

trong đó trả về số lượng phần tử của enum bên trong struct T:)


3

Nếu bạn đang tạo một thư viện mã, thì tôi sẽ sử dụng không gian tên. Tuy nhiên, bạn vẫn chỉ có thể có một enum màu trong không gian tên đó. Nếu bạn cần một enum có thể sử dụng tên chung, nhưng có thể có các hằng số khác nhau cho các lớp khác nhau, hãy sử dụng phương pháp của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.