2009-09-04 31 views
11

Cách thông thường để xác định một số nguyên liên tục sử dụng bên trong một hàm là:Có lý do nào để sử dụng enum để xác định một hằng số trong mã C++ không?

const int NumbeOfElements = 10; 

cùng cho việc sử dụng trong một lớp:

class Class { 
... 
    static const int NumberOfElements = 10; 
}; 

Sau đó nó có thể được sử dụng như là một mảng kích thước cố định bị ràng buộc có nghĩa là nó được biết đến lúc biên dịch.

trình biên dịch trước dài không hỗ trợ cú pháp sau và đó là lý do tại sao sự đếm được sử dụng:

enum NumberOfElementsEnum { NumberOfElements = 10; } 

Bây giờ với hầu hết các trình biên dịch sử dụng rộng rãi hỗ trợ cả trong chức năng const int và trong lớp static const int cú pháp là có bất kỳ lý do để sử dụng enum cho mục đích này?

Trả lời

23

Lý do chủ yếu là ngắn gọn. Trước hết, một enum có thể được ẩn danh:

class foo { 
    enum { bar = 1 }; 
}; 

này có hiệu quả giới thiệu bar như một hằng số tích phân. Lưu ý rằng ở trên ngắn hơn static const int.

Ngoài ra, không ai có thể viết &bar nếu đó là thành viên enum. Nếu bạn làm điều này:

class foo { 
    static const int bar = 1; 
} 

và sau đó là khách hàng của lớp học của bạn thực hiện điều này:

printf("%p", &foo::bar); 

sau đó ông sẽ nhận được một lỗi mối liên kết thời gian biên dịch rằng foo::bar không được định nghĩa (bởi vì, cũng như một lvalue, nó không phải). Trong thực tế, với Tiêu chuẩn như nó hiện đang đứng, bất cứ nơi nào bar được sử dụng trong đó một biểu thức không thể tách rời không phải là yêu cầu (tức lànơi mà nó chỉ được cho phép), nó đòi hỏi một định nghĩa out-of-class của foo::bar. Những nơi biểu thức như vậy là bắt buộc: enum initializers, case nhãn, kích thước mảng trong các loại (ngoại trừ new[]) và đối số mẫu của các loại tích phân. Do đó, sử dụng bar ở bất kỳ nơi nào khác về mặt kỹ thuật đòi hỏi phải có định nghĩa. Xem C++ Core Language Active Issue 712 để biết thêm thông tin - chưa có nghị quyết được đề xuất. Trong thực tế, hầu hết các trình biên dịch những ngày này là khoan dung hơn về điều này, và sẽ cho phép bạn nhận được với hầu hết các "ý thức chung" sử dụng các biến số static const int mà không đòi hỏi một định nghĩa. Tuy nhiên, các trường hợp góc có thể khác nhau, tuy nhiên, rất nhiều người cho rằng tốt hơn là chỉ sử dụng một tên vô danh enum, mọi thứ đều rõ ràng và không có sự mơ hồ chút nào.

+1

Hmm, gcc không phàn nàn về điều này ngay cả với -pantic -Wall -Wextra. Tôi đoán vì nó không thể phát hiện lỗi cho đến khi liên kết thời gian anyway, nó chỉ cho lên trên cố gắng để chẩn đoán mã không di động của loại này. –

+0

Câu trả lời hay. Một điều tốt đẹp khác mà bạn không đề cập một cách rõ ràng là một enum là một rvalue, và do đó không có kho lưu trữ nào được phân bổ cho nó. Nó có thể được tốt đẹp để biết rằng * chắc chắn *, thay vì dựa vào tối ưu hóa trình biên dịch nếu bạn đang làm mẫu lập trình meta và instantiating một số lượng lớn các mẫu lớp. – jalf

+1

Nếu không có định nghĩa cho 'static const int' bên ngoài lớp, sẽ không có bất kỳ bộ nhớ nào được cấp phát cho nó. Ngoài ra, rvalues ​​cũng có thể có lưu trữ được phân bổ cho họ (tạm thời là rvalues, ví dụ, và họ chắc chắn sử dụng lưu trữ). –

-2

dòng dưới cùng - sử dụng const.

biết thêm chi tiết:

Tôi không phải là chuyên gia C++, nhưng đây có vẻ là câu hỏi thiết kế tổng quát hơn.

Nếu nó không phải là phải, và bạn nghĩ rằng có xác suất rất thấp/không tồn tại mà enum sẽ phát triển để có nhiều hơn thì một giá trị, sau đó sử dụng một const thường xuyên. ngay cả khi bạn là sai và tại một số điểm trong tương lai sẽ có nhiều giá trị hơn, làm cho một enum sự lựa chọn đúng - một refactoring đơn giản và bạn thay đổi bạn const để enum.

+0

Đây không phải là về 'enum' so với' const' từ quan điểm thiết kế cấp cao. Đây là tất cả về C++ quirks liên quan đến mỗi cấu trúc. Câu trả lời rõ ràng là sai ở đây. –

3

Tôi nghĩ rằng không có lý do gì để sử dụng enum, và thực sự tốt hơn là sử dụng static const int cho mục đích này, vì enum có kiểu riêng (thậm chí nếu chuyển đổi ngầm thành số nguyên).

+0

Không phải là tôi nhớ bị downvoted, nhưng nó sẽ được tốt đẹp để cho tôi biết lý do tại sao. Cảm ơn. –

+3

Tại sao nó xấu mà một enum có kiểu riêng của nó? Chương trình của bạn có hạn ngạch loại mà bạn không được phép vượt quá không? –

+0

Đồng ý với @Rob Kennedy. Đánh mạnh các hằng số là ** điểm ** của enums. –

9

Xác định hằng số tĩnh trực tiếp trong định nghĩa lớp là một bổ sung sau đó vào C++ và nhiều người vẫn dính vào giải pháp cũ hơn bằng cách sử dụng enum cho điều đó. Thậm chí có thể có một vài trình biên dịch cũ hơn vẫn được sử dụng mà không hỗ trợ các hằng số tĩnh được định nghĩa trực tiếp trong các định nghĩa lớp.

+2

Một số trình biên dịch sẽ không luôn luôn nội tuyến int const tĩnh, trong khi enum sẽ luôn luôn được inline AFAIK. –

5

Trong trường hợp của bạn, tôi cũng sẽ sử dụng hằng số. Tuy nhiên, có những trường hợp khác mà tôi có thể đang thêm các hằng số liên quan khác. Như thế này:

const int TextFile = 1; // XXX Maybe add other constants for binary files etc.? 

Trong trường hợp này, tôi sử dụng một enum ngay lập tức với một giá trị duy nhất, như thế này:

enum FileType { 
    TextFile = 1 
    // XXX Maybe add other values for binary files etc.? 
} 

Lý do được rằng trình biên dịch sau đó có thể đưa ra cảnh báo khi tôi đang sử dụng các giá trị không đổi trong các biểu thức chuyển đổi, như trong:

FileType type; 
// ... 
switch (type) { 
    case TextFile: 
     // ... 
} 

trong trường hợp tôi quyết định thêm một giá trị không đổi có liên quan đến giá trị hiện có (một loại khác nhau của tập tin, trong ví dụ này), hầu như tất cả các trình biên dịch wil l đưa ra cảnh báo vì giá trị mới không được xử lý trong câu lệnh switch.

Nếu tôi đã sử dụng 'int' và hằng số thay vào đó, trình biên dịch sẽ không có cơ hội đưa ra cảnh báo.

5

Lý do duy nhất để sử dụng "enum hack" là các trình biên dịch cũ không hỗ trợ các định nghĩa const trong lớp, như bạn nói trong câu hỏi của mình.Vì vậy, trừ khi bạn nghi ngờ rằng mã của bạn sẽ được chuyển đến một trình biên dịch cũ, bạn nên sử dụng const nơi const là do.

1

Vâng, tính di động lý do chính đáng để sử dụng enum. Thật tuyệt, vì bạn không phải lo lắng liệu trình biên dịch của bạn có hỗ trợ "static const int S = 10" hay không ...

Ngoài ra, theo tôi nhớ, biến tĩnh phải được định nghĩa ở đâu đó, như được khai báo và giá trị enum chỉ được khai báo.

+0

Giá trị 'tĩnh const' của loại tích phân không cần phải được xác định nếu khai báo bao gồm bộ khởi tạo biểu thức hằng số không thể tách rời, nhưng các quy tắc rất tối. Xem câu trả lời của tôi. –

5

Sử dụng enum có một lợi thế. Một kiểu enum là một loại, vì vậy nếu bạn xác định, ví dụ:

enum EnumType { EnumValue1 = 10, EnumValue2 = 20 ... }; 

và bạn có một chức năng như:

void Function1(EnumType Value) 

kiểm tra trình biên dịch mà bạn đang đi qua một thành viên của EnumType enum để chức năng, vì vậy chỉ có giá trị hợp lệ cho tham số Giá trị sẽ là EnumValue1 và EnumValue2. Nếu bạn sử dụng hằng số và thay đổi chức năng thành

void Function1(int Value) 

trình biên dịch sẽ kiểm tra xem bạn đang chuyển int (bất kỳ int, hằng số, biến hoặc chữ) vào hàm.

Loại enum phù hợp để nhóm các giá trị liên quan. Chỉ với một giá trị const, tôi không thấy bất kỳ lợi thế nào.

2

Có sự khác biệt giữa hai yếu tố đó. Enums không có địa chỉ xa như tôi biết. ints const tĩnh làm mặc dù. Vì vậy, nếu ai đó lấy địa chỉ của const static int, bỏ đi const, anh ta có thể sửa đổi giá trị (mặc dù trình biên dịch có thể bỏ qua thay đổi vì anh ta nghĩ đó là const). Điều này tất nhiên là thuần khiết và bạn không nên làm điều đó - nhưng trình biên dịch không thể ngăn chặn nó. Điều này không thể xảy ra với enums.

Và dĩ nhiên - nếu bạn (vì một lý do nào đó) cần địa chỉ của const đó, bạn cần int const tĩnh.

Trong ngắn hạn - enum là một rvalue trong khi const static int là một lvalue. Xem http://www.embedded.com/story/OEG20011129S0065 để biết thêm chi tiết.

+0

Máy khách sẽ không thể lấy địa chỉ của biến thành viên 'static const int' mà không có định nghĩa. Rvalue/lvalue phân biệt là tại chỗ trên, mặc dù. –

+0

Khách hàng sẽ không - nhưng bất kỳ ai duy trì lớp học và thêm mã sau đó. –

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