2010-03-23 35 views
114

Trong đoạn mã sau, Color enum được khai báo trong lớp Car để giới hạn phạm vi của enum và cố gắng không "gây ô nhiễm" không gian tên chung.Khai báo một enum trong một lớp

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à cách hay để giới hạn phạm vi của Color enum không? Hoặc, tôi có nên khai báo nó bên ngoài lớp Car, nhưng có thể trong không gian tên hoặc cấu trúc riêng của nó? Tôi vừa xem qua bài viết này ngày hôm nay, mà chủ trương sau này và thảo luận về một số điểm tốt đẹp về enums: http://gamesfromwithin.com/stupid-c-tricks-2-better-enums.

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

Trả lời

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

  2. Nó không có sự khác biệt. Nếu có một cái toàn cục thì cái cục bộ 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 định nghĩa các hàm đó ngoài định nghĩa lớp thì bạn sẽ cần chỉ định rõ ràng Car::Color trong giao diện của hàm.

+10

2. Có và không. 'Car :: Color getColor()' nhưng 'void Car :: setColor (Color c)' bởi vì trong 'setColor' chúng ta đã có specifier. –

1

Nếu bạn đang tạo mã thư viện, sau đó tôi sẽ sử dụng không gian tên. Tuy nhiên, bạn vẫn có thể chỉ có một màu Enum bên trong không gian tên đó. Nếu bạn cần một enum có thể sử dụng một 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 cách tiếp cận của bạn.

6

Nói chung, tôi luôn đặt enums vào struct. Tôi đã thấy một số nguyên tắc bao gồm "tiền tố".

enum Color 
{ 
    Clr_Red, 
    Clr_Yellow, 
    Clr_Blue, 
}; 

Luôn nghĩ này trông giống như C hướng dẫn hơn C++ người (đối với một vì chữ viết tắt và cũng vì không gian tên trong C++).

Vì vậy, để giới hạn phạm vi bây giờ chúng tôi có hai lựa chọn:

  • namespace
  • struct/classes

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

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

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

mà trả về số phần tử của enum bên trong struct T :)

58

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 liệt kê khác nhau, hoặc liệt kê của bạn với bất kỳ kiểu 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; 
}; 

Cách 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 vĩ mô để 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), 

Cách sử dụng:

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

Một số tài liệu tham khảo hữu ích:

  1. Herb Sutter, Jum Hyslop, C/C++ Người dùng Journal, 22 (5), tháng 5 năm 2004
  2. Herb Sutter, David E. Miller, Bjarne Stroustrup mạnh Typed Enums (hiệu đính 3), tháng 7 năm 2007
+0

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

+0

Tôi cũng thích điều này. Cảm ơn bạn đã tham khảo. – anio

+1

Bạn nói: * "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 bảng liệt kê khác nhau ..." * Tại sao bạn nghĩ nó là một tính năng tốt? Tôi nghĩ 'if (c2 == Màu: : Màu đỏ) 'là hợp lý và phải biên dịch, nhưng trong ví dụ của bạn nó không có cùng một đối số cho phép gán! – Nawaz

66

Ngày nay - sử dụng C++ 11 - bạn có thể sử dụng enum class cho việc này:

enum class Color { RED, BLUE, WHITE }; 

AFAII này thực hiện chính xác những gì bạn muốn.

Các vấn đề liên quan