Подтвердить что ты не робот

Где объявлять/определять константы области класса в С++?

Мне интересно узнать о преимуществах/недостатках различных деклараций констант и вариантов определения в С++. В течение самого долгого времени я просто объявлял их в верхней части файла заголовка перед определением класса:

//.h
const int MyConst = 10;
const string MyStrConst = "String";
class MyClass {
...
};

Несмотря на то, что это загрязняет глобальное пространство имен (которое, как я знаю, плохо, но никогда не нашел список стилей, почему это плохо), константы по-прежнему будут привязаны к отдельным единицам перевода, поэтому файлы, которые не включить этот заголовок не будет иметь доступа к этим константам. Но вы можете получить коллизии имен, если другие классы определяют константу с тем же именем, что, возможно, не так уж плохо, поскольку это может быть хорошим показателем области, которая может быть реорганизована.

Недавно я решил, что было бы лучше объявить специфические для класса константы внутри самого определения класса:

//.h
class MyClass {
    public:
         static const int MyConst = 10;
...
    private:
         static const string MyStrConst;
...
};
//.cpp
const string MyClass::MyStrConst = "String";

Видимость константы будет скорректирована в зависимости от того, используется ли константа только внутри класса или требуется для других объектов, которые используют класс. Это то, что я думаю, является лучшим вариантом сейчас, главным образом потому, что вы можете сохранить внутренние константы класса, приватные для класса, и любые другие классы, использующие общедоступные константы, будут иметь более подробную ссылку на источник константы (например, MyClass:: MyConst). Он также не будет загрязнять глобальное пространство имен. Хотя у него есть недостаток в требовании неинтегральной инициализации в файле cpp.

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

Просто ищите мнения и, возможно, другие варианты, которые я еще не рассматривал.

4b9b3361

Ответ 1

Ваше утверждение о том, что объявление целой константы как статического члена класса "в ущерб требованию неинтегральной инициализации в файле cpp", не является точно твердым, так сказать. Это требует определения в файле cpp, но это не "вред", это вопрос ваших намерений. Объект уровня const уровня пространства имен в С++ по умолчанию имеет внутреннюю привязку, что означает, что в вашем исходном варианте декларация

const string MyStrConst = "String"; 

эквивалентно

static const string MyStrConst = "String"; 

то есть. он определит независимый объект MyStrConst в каждой единицы перевода, в который включен этот заголовочный файл. Вы знаете об этом? Это было ваше намерение или нет?

В любом случае, если вам не нужен отдельный объект в каждой единицы перевода, объявление константы MyStrConst в вашем исходном примере не является хорошей практикой. Обычно вы помещаете в файл заголовка не определяющее объявление

extern const string MyStrConst; 

и предоставить определение в файле cpp

const string MyStrConst = "String";

поэтому убедитесь, что вся программа использует один и тот же постоянный объект. Другими словами, когда дело доходит до нецелых констант, обычной практикой является их определение в файле cpp. Таким образом, независимо от того, как вы его объявляете (в классе или вне), вам обычно всегда приходится иметь дело с "ущербом" от необходимости определять его в файле cpp. Конечно, как я сказал выше, с константами пространства имен вы можете уйти от того, что у вас есть в первом варианте, но это будет всего лишь примером "ленивого кодирования".

Во всяком случае, я не думаю, что есть причина слишком усложнять проблему: если константа имеет очевидное "вложение" в класс, она должна быть объявлена ​​как член класса.

P.S. Спецификаторы доступа (public, protected, private) не контролируют видимость имени. Они контролируют только его доступность. Имя остается видимым в любом случае.

Ответ 2

Загрязнение глобального пространства имен плохо, потому что кто-то (например, автор используемой библиотеки) может захотеть использовать имя MyConst для другой цели. Это может привести к серьезным проблемам (библиотеки, которые нельзя использовать вместе и т.д.).

Ваше второе решение, безусловно, лучше всего, если константы связаны с одним классом. Если это не так просто (подумайте о физических или математических константах, не связанных с классом в вашей программе), решение пространства имен лучше этого. BTW: если вы должны быть совместимы с более старыми компиляторами на С++, помните, что некоторые из них не могут использовать интегральную инициализацию в файле заголовка - вы должны инициализировать файл С++ или использовать старый трюк enum в этом случае.

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

Ответ 3

Загрязнение глобального пространства имен должно быть само собой разумеющимся. Если я включаю заголовочный файл, я не хочу сталкиваться или отлаживать конфликты имен с константами, объявленными в этом заголовке. Эти типы ошибок действительно расстраивают и иногда трудно диагностировать. Например, мне когда-то приходилось ссылаться на проект, который был указан в заголовке:

#define read _read

Если ваши константы являются загрязнением пространства имен, это ядерные отходы пространства имен. Проявление этого было серией очень странных ошибок компилятора, жалующихся на отсутствие функции _read, но только при связывании с этой библиотекой. Мы в конечном итоге переименовали функции чтения в нечто другое, что не сложно, но должно быть ненужным.

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

Я также видел, как люди помещали константы в свой собственный класс, который можно реализовать как синглтон. Это для меня, кажется, работает без вознаграждения, язык предоставляет вам некоторые возможности для объявления констант.

Ответ 4

Лично я использую ваш второй подход; Я использовал его в течение многих лет, и он хорошо работает для меня.

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

Ответ 5

Вы можете объявить их как глобальные переменные в файле С++, если они не указаны в заголовке. Затем они являются частными для этого класса и не будут загрязнять глобальное пространство имен.

Ответ 6

Если только один класс будет использовать эти константы, объявите их как static const внутри тела класса. Если куча связанных классов будет использовать константы, объявите их либо внутри класса/структуры, которая содержит только константы и методы использования или внутри выделенного пространства имен. Например,

namespace MyAppAudioConstants
{
     //declare constants here
}

Если они являются константами, используемыми всем приложением (или значительными фрагментами), объявляйте их внутри пространства имен в заголовке, который (либо неявно, либо явно) включен везде.

namespace MyAppGlobalConstants
{
    //declare constants here
}

Ответ 7

не загрязняют глобальное пространство имен, загрязняют локальные.

namespace Space
  {
  const int Pint;
  class Class {};
  };

Но практически...

class Class
  {
  static int Bar() {return 357;}
  };