2009-10-04 2 views
3

С точки зрения практики кодирования, в каких контекстах глобальные константы предпочитают перечисление и наоборот?Глобальные константы против перечисления

Например, предположим, что мне нужен способ выразить различные спрайты на плитки в глобальном масштабе. Я мог бы сделать ...

const int TILE_RED = 0; 
const int TILE_GREEN = 1; 
const int TILE_BLUE = 2; 
const int TILE_CENTER = 3; 
const int TILE_TOP = 4; 
const int TILE_TOPRIGHT = 5; 
const int TILE_RIGHT = 6; 
const int TILE_BOTTOMRIGHT = 7; 
const int TILE_BOTTOM = 8; 
const int TILE_BOTTOMLEFT = 9; 
const int TILE_LEFT = 10; 
const int TILE_TOPLEFT = 11; 

или

enum Tile { TILE_RED, TILE_GREEN, TILE_BLUE, TILE_CENTER, TILE_TOP, TILE_TOPRIGHT 
TILE_RIGHT, TILE_BOTTOMRIGHT, TILE_BOTTOM, TILE_BOTTOMLEFT, TILE_LEFT, TILE_TOPLEFT }; 

Очевидно, что мы предпочитаем постоянные и перечислений в макрос, но то, что о том, когда дело доходит до констант и перечислений? Какие ситуации предпочитают что? Я читал here, что постоянные объекты представляют небольшой риск сделать вашу программу медленнее, но я хотел бы услышать мысли других.

Я использовал этот пример, в частности, потому что это большой набор связанных объектов - пижама кошки для перечисления.

ответ

4

Одна из приятных вещей в перечислениях состоит в том, что они переносимы между C и C++, в то время как элементы const не могут использоваться в C во всех местах, которые могут вам понравиться (например, объявления массива). Поэтому для заголовков, которые я хотел бы работать на C или C++, я имел тенденцию использовать перечисления, предпочитая объявления const или макроопределения. На самом деле я использовал их, независимо от того, предназначен ли заголовок только для C++ или нет (одно меньшее решение, о котором я должен думать).

Наличие типа переименования неоднозначно, это не проблема очень часто - если вы перегружаетесь на основе разных разных типов интегралов, у вас появятся потенциальные проблемы с перечислениями, и в этом случае объекты const, вероятно, будут лучше , Но я не помню, как в последний раз мне нужно было различное поведение для разных типов одного и того же числа (т. Е. Обработка 5U иначе, чем 5 или 5L). Я думаю, что тип перегрузки действительно наблюдается только в проблемах с головоломкой/интервью, или это код, который будет порождать ошибки в любом случае, используете ли вы перечисления или нет.

Итак, в нижней строке я предпочел перечисления, но удачи, чтобы ваши сотрудники перестали использовать макросы. Использование макросов для именованных констант довольно хорошо укоренилось в культуре C/C++, и даже несмотря на то, что они сильно загрязняют пространство имен, недостаточно реальных проблем с текстом, чтобы убедить многих людей даже думать об изменении привычки.

2

Используйте перечисления, когда значение константы либо не имеет значения, либо не является последовательным, как в вашем примере.

Используйте константы, если вам нужны специальные постоянные значения, присвоенные идентификатору.

0

Неявные перечисления могут вызывать некоторые проблемы совместимости с платформой, а также они не являются безопасными для типов. Глобальные константы являются безопасными по типу и обычно предпочтительны. Однако, если вы упускаете это из виду, перечисления обычно используются для связанных вещей и констант для более несвязанных вещей.

Пример, когда вы используете перечисления:

enum Colors { 
COLOR_RED=0xFF0000, 
COLOR_GREEN=0x00FF00, 
COLOR_BLUE=0x0000FF 
} 

Пример, когда вы будете использовать глобальные consts:

volatile const void *VRAM=0x00FC0000; 

Наконец, мой совет, что если вы действительно заботитесь о совместимости платформы, а затем использовать глобальным consts.

+2

«Неявные перечисления могут вызывать некоторые проблемы совместимости с платформой» - примеры, пожалуйста. Также, что вы подразумеваете под «безопасным типом» и как глобальные константы больше? –

+0

«Не явный» просто означает, что перечисления не имеют типа. Проблема совместимости с платформой была обнаружена в ящиках Linux, и для этого было сделано исправление. Хороший компилятор сообщит об этом вам, если вы попытаетесь скрыть листинг const. – aviraldg

+0

Не могли бы вы указать некоторую информацию о исправлении совместимости платформы libc, о котором вы упоминали? Я хотел бы узнать об этом. –

4

Два смежных преимущества перечислений являются их самодокументирующимся природы, а также тот факт, что они сохранить пространство имен понятнее. В основном перечисления подобны пучкам семантически связанных констант, в пределах их собственного пространства имен. Используя перечисления в intefaces, вы неявно указываете, какой набор значений будет ожидаться.

Редактировать: Исправление! (Я делал слишком много C# и в последнее время, и недостаточно C/C++!)
С C и C++ идентификаторы в перечислении обламываются как обычные переменные и константы и поэтому должны отличаться от того, что любой другой идентификатор в том же объеме, включая идентификаторы в других списках перечислений. Это отличается от более современных языков, где перечисление вводит свое собственное пространство имен. Понятие о том, что перечисление C/C++ помогает с сохранением пространства имен, является некорректным. Спасибо, Майкл Берр, за это.

Основным недостатком перечислений является то, что они не так легко переносимы. Постоянный тип и значение однозначно определены, с перечислениями меньше ясности.

+0

Как enum сохраняет пространство имен более четким, чем const? Они оба попадают в пространство имен, в котором они находятся, - вы не можете иметь константу и перечисление с тем же именем на одном и том же уровне пространства имен. Помните, что здесь важно имя фактического перечисления (например, 'TILE_RED'), а не имя типа перечисления (например,' enum Tile'). –

+0

@Michael Burr Упс! Как сказано в моем редактировании, я принимаю некоторые функции C# как должное. Вы правы, в C/C++ перечисления не представляют свое собственное пространство имен, поэтому индексы в списке перечислений должны совместно использовать пространство имен основной области. Преимущества перечислений в C/C++, следовательно, довольно тонкие, неудивительно, что я не использовал их так много, особенно учитывая потенциальные проблемы взаимодействия с смешанными проектами компилятора. Спасибо, что поддержал меня честно. – mjv

1

Самое большое преимущество перечисления состоит в том, что он может быть принудительно применен компилятором, но это не так с константой.

+0

AFAIK компилятор c не разрешается делать это, поскольку переменная, типизированная перечислением, определяет целочисленный тип некоторой длины бит (в зависимости от перечисления), но не подменю целочисленного типа. – Lothar

0

Если нет специальной причины для обратной совместимости, я предпочитаю передовую совместимость. В этом случае использование глобальных констант больше не зависит от компилятора, но я голосую за перечисления по нескольким причинам:
1. У consts могут быть разные типы. Все, что требуется, - это плохой поиск - замена, когда вы хотите заменить тип вашего перечисления. Это может привести к некоторым неожиданным последствиям (считать подписанный/неподписанный и размер значения). в перечислениях применяется один тип.
2. строго типизированные перечисления представлены в C++ 0x. Для этого уже существуют некоторые реализации для C++.
3. перечисления, ИМХО, очень трудно писать неясным способом. Вы не можете сказать это на consts (разбросаны по нескольким файлам и т. Д.).

BTW, Если вы используете const, я предпочитаю использовать статические константы внутри класса (а не глобального).