2009-05-22 55 views
31

Tại sao mọi người sử dụng enums trong C++ làm hằng số khi họ có thể sử dụng const?Tại sao mọi người sử dụng enums trong C++ như hằng số trong khi họ có thể sử dụng const?

+0

Tôi biết điều này là một chủ đề thực sự cũ, nhưng bạn có thể đưa ra một ví dụ? Khi tôi đọc câu hỏi này, tôi đã suy nghĩ dọc theo các dòng mã trả về một int từ một hàm, nhưng sử dụng một enum để xác định các 'phiên bản' cụ thể của giá trị trả về, ví dụ: Một số câu trả lời dưới đây dường như giải quyết các vấn đề hoàn toàn khác nhau. Theo ý kiến ​​của tôi, nó sai khi sử dụng một enum theo cách đó trừ khi, như mọi người nói, trình biên dịch của bạn bị hạn chế trong chức năng của nó. – cosimo193

+0

Có thể trùng lặp của [Tôi có nên sử dụng #define, enum hoặc const?] (Https://stackoverflow.com/questions/112433/should-i-use-define-enum-or-const) –

Trả lời

20

Một liệt kê ngụ ý tập hợp các hằng số liên quan, vì vậy thông tin bổ sung về mối quan hệ phải hữu ích trong mô hình của vấn đề trong tầm tay.

+30

Hm, điều đó không nhìn như một câu trả lời cho câu hỏi (mặc dù nó đã được chấp nhận). Mọi người sử dụng enums nơi họ có thể sử dụng 'const' và các giá trị là ** không ** liên quan. Thông thường bạn sẽ thấy 'enum {SOMETHING = 2232; } '(như thế; enum chưa đặt tên chỉ với một giá trị) thay vì' const int SOMETHING = 2232; '.Đó là bởi vì enum không bao giờ được lưu trữ trong khi biến const vẫn là một biến và sẽ nhận được (tĩnh) lưu trữ nếu trình biên dịch không thể proove nó sẽ không cần một, mà nó thường không thể. –

+0

Một lý do khác là biến "POD" là một tính năng C++ mới hơn và nhiều cơ sở mã cũ hơn (và những người lập trình thích khả năng tương thích cao hơn) vẫn tồn tại. –

-1

Một lý do là const đòi hỏi nhiều gõ:

enum { Val1, Val2, Val3 }; 

... so ...

const int Val1=0, Val2=1, Val3=2; 
+1

Đó không phải là lý do duy nhất. Ngoài ra, không có sự khác biệt lớn trong việc gõ. –

34

Enums nhiều loại khác nhau, vì vậy bạn có thể làm loại theo định hướng những thứ như quá tải với chúng:

enum Color { Red,Green,Blue }; 
enum Size { Big,Little }; 

void f(Color c) { 
} 

void f(Size s) { 
} 

int main() { 
    f(Red); 
    f(Big); 
} 
+5

Đây không phải là câu hỏi được đặt ra. Câu hỏi đặt ra là: tại sao mọi người viết những thứ như: enum {Margin = 50}; – Claudio

20

Cũng có lý do lịch sử khi xử lý mẫu aprogramming. Một số trình biên dịch có thể sử dụng các giá trị từ một enum, nhưng không phải là một const int tĩnh để khởi tạo một lớp.

template <int N> 
struct foo 
{ 
    enum { Value = foo<N-1>::Value + N }; 
}; 

template <> 
struct foo<0> 
{ 
    enum { Value = 0; } 
}; 

Bây giờ bạn có thể làm điều đó một cách hợp lý hơn:

template <int N> 
struct foo 
{ 
    static const int Value = foo<N-1>::Value + N; 
}; 

template <> 
struct foo<0> 
{ 
    static const int Value = 0; 
}; 

Một lý do khác có thể, là một const int tĩnh có thể có bộ nhớ dành cho nó trong thời gian chạy, trong khi một enum là không bao giờ có một vị trí bộ nhớ thực tế dành riêng cho nó, và sẽ được xử lý tại thời gian biên dịch. Xem this related question.

10

Enums mang tính mô tả hơn khi được sử dụng. Xem xét:

int f(int fg, int bg) 

so

int f(COLOR fg, COLOR bg) 

Bên cạnh đó, sự đếm cho thêm một chút kiểu an toàn, bởi vì

  • số nguyên không phải là mặc nhiên chuyển đổi thành enum loại
  • enum của một loại không chuyển đổi hoàn toàn thành enum của loại khác
+0

Đây là một chủ đề cũ, nhưng hai câu lệnh ở phần cuối của câu trả lời này là sai và cần sửa chữa. – motiz88

+4

"số nguyên không chuyển đổi hoàn toàn thành loại enum" và "enum của một loại không chuyển đổi hoàn toàn thành enum của một loại khác" - sai. Đồng bằng 'enum' s sẽ âm thầm chuyển đổi sang/từ số nguyên, trong C++ như trong C. Vì vậy, họ nghiêm chỉnh _don't_ cung cấp sự an toàn này. Tuy nhiên, trong C++ 11, có 'lớp enum' là kiểu C++ thích hợp" tưởng tượng lại "của' enum': Các chuyển đổi ngầm đã biến mất và các tên giá trị bổ sung phải luôn đủ điều kiện. Điều này tương tự như C# 'enum', và tránh các vấn đề ô nhiễm tên va chạm/không gian tên phát sinh với' enum' cũ của C. – motiz88

+0

@ motiz88 - Tôi nghĩ bạn có thể bị nhầm lẫn với điều này. Hãy thử mã này trên gcc (bạn sẽ cần tự định dạng lại nó): int main() {enum MyEnum1 {VAL11, VAL12, VAL13}; enum MyEnum2 {VAL21, VAL22, VAL23, VAL24}; int int1 = VAL11; MyEnum1 enum1 = 3; MyEnum2 enum2 = VAL11; enum2 = enum1; int int2 = enum1; trả về 0; } Giá trị enum chuyển đổi hoàn toàn thành số nguyên, nhưng không ngược lại, và "loại enum" không ngầm chuyển đổi giữa nhau. Về nguyên tắc tôi tin rằng ASK là chính xác ở đây, nhưng tôi không nghĩ rằng nó thực sự là một câu trả lời cho câu hỏi của op! – cosimo193

4

enums cũng có thể được sử dụng làm tên loại. Vì vậy, bạn có thể định nghĩa một hàm nhận enum như một tham số, làm cho nó rõ ràng hơn các loại giá trị nên được đưa ra làm đối số cho hàm, so với các giá trị được định nghĩa dưới dạng biến const và hàm chỉ chấp nhận "int" như một đối số.

xem xét:

enum my_new_fangled_type { 
    baz = 0, 
    meh = 1 
}; 

void foo (my_new_fangled_type bar) // bar can be a value listed in the enum 
{ 
    ... 
} 

so:

int const baz = 0; 
int const meh = 1; 

void foo (int bar) // what are valid values for bar? 
{ 
    ... 
} 
+1

'typedef int my_new_fangled_type; void foo (my_new_fangled_type bar); 'Vấn đề được giải quyết, không cần enum, và tôi có thể thay đổi biểu diễn bộ nhớ bằng cách thay thế' typedef int' bằng 'typedef uchar' hoặc một số thứ như vậy. :) – weberc2

0

Sử dụng một enum tài liệu sự lựa chọn hợp lệ một cách ngắn gọn và cho phép trình biên dịch để thực thi chúng.

Nếu chúng đang sử dụng enum lưu trữ các hằng số toàn cầu, như Pi chẳng hạn, thì tôi không biết mục tiêu của chúng là gì.

+1

enum là một loại không thể thiếu, tôi không tin rằng nó có thể lưu trữ một hằng số như Pi mà không làm giảm đáng kể độ chính xác :) – ASk

+0

chúng có thể lưu trữ 314159 và chỉ div 10^5 mỗi lần: P hy vọng ví dụ cho đúng ý tưởng về những gì tôi có nghĩa là bởi các hằng số toàn cầu, tuy nhiên. – dss539

10

Tôi thích hành vi tự động có thể được sử dụng với sự đếm, ví dụ:

enum {NONE, START, HEY, HO, LAST}; 

Sau đó, nó rất dễ dàng để lặp cho đến khi LAST, và khi một trạng thái mới (hoặc bất kỳ được biểu diễn) được thêm vào, logic thích nghi.

for (int i = NONE; i < LAST; i++) 
{ 
    // Do stuff... 
} 

Thêm một cái gì đó ...

enum {NONE, START, HEY, WEE, HO, LAST}; 

Vòng lặp điều chỉnh ...

+0

Trừ khi ai đó vô tình thêm chữ cái enum mới vào cuối danh sách hoặc quyết định cung cấp các giá trị không tiếp giáp cho các chữ cái (ví dụ: enum {} NONE = 0, START = 4, HEY = 7 etc ....). – cosimo193

5

Trước khi các nhà cung cấp trình biên dịch thực hiện các tiêu chuẩn ISO/IEC 14882: 1998 C++ chuẩn, mã này để xác định một hằng số trong phạm vi lớp dẫn đến lỗi biên dịch:

class Foo { 
    static const int MAX_LEN = 80; 
    ... 
}; 

Nếu hằng số là một kiểu số nguyên, công việc kludgy là d efine nó trong một enum bên trong lớp:

class Foo { 
    enum { 
     MAX_LEN = 80 
    }; 
    ... 
}; 
+0

Hằng số không tĩnh không thể được khởi tạo theo cách đó. Tôi tin rằng bạn có nghĩa là "static const int Val1". Ngoài ra, có những hạn chế trong việc sử dụng phương pháp khởi tạo trong lớp này - biểu tượng cho Val1 không đảm bảo được tạo. – ASk

+0

@ASk: Vấn đề là biểu tượng cho "static const int Val1" không được bảo đảm để ** không ** được tạo ra, do đó, lập trình viên sử dụng enum thay vào đó, bởi vì điều đó không tạo ra biểu tượng nào cả. –

41

Bruce Eckel đưa ra một lý do tại Thinking in C++:

In older versions of C++, static const was not supported inside classes. This meant that const was useless for constant expressions inside classes. However, people still wanted to do this so a typical solution (usually referred to as the “enum hack”) was to use an untagged enum with no instances. An enumeration must have all its values established at compile time, it’s local to the class, and its values are available for constant expressions. Thus, you will commonly see:

#include <iostream> 
using namespace std; 

class Bunch { 
    enum { size = 1000 }; 
    int i[size]; 
}; 

int main() { 
    cout << "sizeof(Bunch) = " << sizeof(Bunch) 
     << ", sizeof(i[1000]) = " 
     << sizeof(int[1000]) << endl; 
} 

[Chỉnh sửa]

Tôi nghĩ rằng nó sẽ là công bằng hơn để liên kết trang web của Bruce Eckel của : http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html.

2

Một số trình gỡ lỗi sẽ hiển thị tên điều tra thay vì giá trị của nó khi gỡ lỗi. Cái này có thể rất hữu ích. Tôi biết rằng tôi thà thấy day_of_week = MONDAY hơn day_of_week = 1.

2

Đó là một phần vì trình biên dịch cũ không hỗ trợ việc khai báo của một lớp thật liên tục

class C 
{ 
    const int ARealConstant = 10; 
}; 

vì vậy đã phải làm điều này

class C 
{ 
    enum { ARealConstant = 10 }; 
}; 

Vì lý do này, nhiều thư viện di động tiếp tục sử dụng hình thức này .

Lý do khác là sự đếm có thể được sử dụng như một thiết bị cú pháp thuận tiện để tổ chức hằng lớp thành những người có liên quan, và những người mà không phải là

class DirectorySearcher 
{ 
    enum options 
    { 
    showFiles = 0x01, 
    showDirectories = 0x02, 
    showLinks = 0x04, 
    }; 
}; 

vs

class Integer 
{ 
    enum { treatAsNumeric = true }; 
    enum { treatAsIntegral = true }; 
    enum { treatAsString = false }; 
}; 
Các vấn đề liên quan