Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Лучший подход для определения константы (используемой в постоянном выражении) в классе?

Автор вопроса: aJ.Ответов: 7

Я пытаюсь определить константу BUFFER_LENGTH для моего класса для данного варианта использования.

//1. Using preprocessor declaration
//#define BUFFER_LENGTH  12

//2.Global constant
//const int BUFFER_LENGTH  = 12;
class MyRequest
{
public:
    //3. Define an in-class constant
    //static const int BUFFER_LENGTH = 12;

    //4. Declare an enum constant
    enum
    {
        BUFFER_LENGTH = 12
    };

    MyRequest()
    {
        strcpy(mBuffer, "TestString");
        printf("Buffer: %s, BUFFER_LENGTH = %d",mBuffer, BUFFER_LENGTH);
    }
private:
    char mBuffer[BUFFER_LENGTH];
};

Я только что перечислил различные способы определения константы для класса.

1. Using Preprocessor constant
2. Using Global constant
3. Using in-class constant
4. using an enum.

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

Спасибо,

c++constants

Ответы

Ответ 1 · рейтинг 10 · xtofl

Тип enumerate не предназначен для определения числовой константы, хотя он (ab) часто используется для этого в метапрограммировании шаблонов.

Если значение константы связано с классом, я бы определил его там. Тогда у вас все еще есть два варианта:

 class WithConst {
 public:

     // 1. as a const static member variable
     static const int sc_nNumber = 100; // I can initialize here for
                                        // integral-types only

     // 2. as a static member function - possibly inlined.
     static int sf_nNumber() { return 100; }
 };

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

Ответ 2 · рейтинг 9 · j_random_hacker

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

static const int BUFFER_LENGTH = 12;

or

enum { BUFFER_LENGTH = 12 };

внутри определения класса.

В первом нет особой пользы, за исключением того, что вы можете явно управлять типом. enum заставляет C++ выбирать для вас неопределенный целочисленный "базовый тип" - он может быть таким же маленьким, как char, если ваше перечисление содержит только небольшие значения, хотя эмпирически большинство компиляторов по умолчанию будут использовать int.

Ответ 3 · рейтинг 3 · sharptooth

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

Ответ 4 · рейтинг 2 · qwerty

Я читал в "Thinking in C++", что "enum-hack" использовался в прошлом, потому что некоторые компиляторы не поддерживали члены класса "static const":
http://www.linuxtopia.org/online_books/programming_books/thinking_in_c++/Chapter08_023.html

Поэтому, если вы используете устаревший компилятор или хотите его поддерживать, используйте enum-hack. (Я понятия не имею, НАСКОЛЬКО они должны быть старыми, чтобы не поддерживать статическую константу)

Ответ 5 · рейтинг 1 · D.Shawley

Я не уверен, что они полностью взаимозаменяемы в этом конкретном случае. Поскольку вы основываете размер члена массива на константе, я считаю, что это должно быть перечисляемое значение. У меня нет времени искать его в стандарте, но я был бы удивлен, если бы вы могли использовать элемент int в качестве размера массива, даже если он равен static const, поскольку фактическое значение может быть не видно в заголовке.

// === in myclass.h
class MyClass {
public:
    static const int MY_SIZE;
private:
    int ary[MY_SIZE];
};

// === in myclass.cpp
/*static*/ const int MyClass::MY_SIZE = 10;

// === in otherclass.cpp
void OtherClass::operation(MyClass& obj) {
    std::cout << "Sizeof(MyClass) = " << sizeof(obj) << std::endl;
}

Я не думаю, что компилятор может скомпилировать otherclass.cpp, не скомпилировав myclass.cpp.

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

Редактировать

Я только что взглянул на Standard, пока ел обед (спасибо за подталкивание, Дэвид)

целочисленное константное выражение может включать только литералы (2.13), перечислители, const переменные или статические элементы данных целочисленного или перечисляемого типов, инициализированные константными выражениями (8.5), нетиповые параметры шаблона интегрального или перечисляемого типы и sizeof выражения.

Похоже, что и константа, и перечисление будут работать при условии, что вы предоставите инициализатор константы в объявлении (или это определение?).

Ответ 6 · рейтинг 1 · dmityugov

Использование const int может быть менее эффективным, чем использование enum, ниже приведена программа, демонстрирующая это. Скомпилированный с помощью Metrowerks CodeWarrior 8.x для Windows, он показывает, что объект класса, который определяет константу как const int, занимает на 4 байта памяти больше, чем аналогичный класс, который определяет эту константу как enum:

#include <stdio.h>
#include <stdlib.h>

class foo {
    enum { MY_CONST = 1 };
    int x;
    public:
    foo();
};
class bar {
    const int MY_CONST;
    int x;
    public:
    bar();
};

int main() {
    printf( "%u %u\n", sizeof( foo), sizeof( bar));
    return EXIT_SUCCESS;
}

Производит: "4 8"

Конструкторы были добавлены для предотвращения агрессивной оптимизации компилятором. Поскольку программа не создает объекты этих типов, конструкторы не обязательно определять в отдельном модуле компиляции. То же самое верно для const int

Ответ 7 · GregC

Читая предыдущие сообщения, я заметил, что никто не упомянул трюк с "перечислением в пространстве имен". Если вам нравятся перечисления, потому что вы работаете со старым компилятором (у меня был такой опыт работы с платформой встроенного программирования VxWorks/Tornado), то послушайте: вы можете избежать конфликтов имен, поместив перечисление внутри пространства имен или (если пространства имен не являются поддерживается либо) внутри класса.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы