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

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

//.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 файле.

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

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

60
задан bsruth 11 January 2010 в 17:18
поделиться

7 ответов

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

const string MyStrConst = "String"; 

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

static const string MyStrConst = "String"; 

I.E. Он будет определять независимую mystrconst объект в каждом блоке перевода, в который включен этот файл заголовка. Вы знаете об этом? Был ли это ваше намерение или нет?

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

extern const string MyStrConst; 

и предоставляют определение в файле CPP

const string MyStrConst = "String";

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

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

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

45
ответ дан 24 November 2019 в 17:53
поделиться

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

namespace MyAppAudioConstants
{
     //declare constants here
}

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

namespace MyAppGlobalConstants
{
    //declare constants here
}
2
ответ дан 24 November 2019 в 17:53
поделиться

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

#define read _read

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

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

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

5
ответ дан 24 November 2019 в 17:53
поделиться

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

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

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

10
ответ дан 24 November 2019 в 17:53
поделиться

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

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

2
ответ дан 24 November 2019 в 17:53
поделиться

Если это стандартное приложение WinForms, то все, что вам действительно нужно сделать в своем приложении, - это добавить обработчики событий в вашей форме для драгенератора и DrackDrop.

Внутри драттера вы захотите проверить тип объекта, чтобы убедиться, что это имя файла:

private void MyForm_DragEnter(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(DataFormats.FileDrop))
    {
        string[] files = e.Data.GetData(DataFormats.FileDrop) as string[];
        if (files != null)
        {
            // Do additional checks here if needed, like check extensions
            e.Effect = DragDropEffects.Copy;
            return;
        }
    }

    e.Effect = DragDropEffects.None;
}

, затем в обработчике DrackDrop, я просто сохранил бы имена файлов, а затем активируйте таймер. Это позволяет DRAGROP возвращать немедленно, так что другое приложение (в вашем примере, Windows Explorer) не зависает, пока вы выполняете какую-либо обработку в файле, который может занять время. Источник сопротивления не будет возвращаться до завершения DrackDrop.

private void MyForm_DragDrop(object sender, DragEventArgs e)
{
    string[] files = e.Data.GetData(DataFormats.FileDrop) as string[];
    if (files != null)
    {
        _filesToProcess.Text = files[0];  // Assuming this is declared at the Form level

        // Schedule a timer to fire in a few miliseconds as a simple asynchronous method
        _DragDropTimer.Interval = 50;
        _DragDropTimer.Enabled = true;
        _DragDropTimer.Start();
        Activate();  // Activates the form and gives it focus
    }
}
-121--3418721-

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

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

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

class Class
  {
  static int Bar() {return 357;}
  };
-2
ответ дан 24 November 2019 в 17:53
поделиться

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

2
ответ дан 24 November 2019 в 17:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: