Как инициализировать константную переменную-член в классе?

105
#include <iostream>

using namespace std;
class T1
{
  const int t = 100;
  public:

  T1()
  {

    cout << "T1 constructor: " << t << endl;
  }
};

Когда я пытаюсь инициализировать переменную-член const значением t100. Но это дает мне следующую ошибку:

test.cpp:21: error: ISO C++ forbids initialization of member t
test.cpp:21: error: making t static

Как я могу инициализировать constзначение?

Чайтанья
источник
8
с С ++ 11 это возможно, проверьте эту ссылку stackoverflow.com/questions/13662441/…
Капил

Ответы:

123

В constпеременной определяет , является ли переменная изменяемым или нет. Присвоенное постоянное значение будет использоваться каждый раз при обращении к переменной. Присвоенное значение нельзя изменить во время выполнения программы.

Объяснение Бьярна Страуструпа кратко резюмирует это:

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

constПеременная должна быть объявлена в классе, но она не может быть в нем определены. Нам нужно определить переменную const вне класса.

T1() : t( 100 ){}

Здесь присвоение t = 100происходит в списке инициализаторов, задолго до инициализации класса.

Динкар Тхакур
источник
3
Не могли бы вы немного уточнить последнее утверждение, которое Here the i = 10 assignment in initializer list happens much before the class initilizaiton occurs.я не понял. И в основном такое разрешение определений внутри класса зависит от компилятора, верно?
Чайтанья
3
Какое задание i = 10?
Daniel Daranas
В моем классе есть константы, которые я инициализирую описанным выше способом. Однако когда я пытаюсь создать объект этого класса, я получаю сообщение об ошибке operator = function not foundв VC ++. В чем может быть проблема?
Рохит Шинде,
4
Когда вы используете чьи-то точные слова без указания авторства, это называется плагиатом. Пожалуйста, используйте правильную атрибуцию - см. Stroustrup.com/bs_faq2.html#in-class и stackoverflow.com/questions/13662441/…
Таная,
Да, я тоже совершенно не понимаю код в ответе - что это, черт возьми? Можно ли его разместить в реализации файла cpp?
Томаш Зато - Восстановите Монику
50

Что ж, вы могли бы это сделать static:

static const int t = 100;

или вы можете использовать инициализатор члена:

T1() : t(100)
{
    // Other constructor stuff here
}
Фред Ларсон
источник
2
Для его использования (и / или намерений) было бы гораздо лучше сделать его статичным.
Марк Гарсия
@FredLarson Это похоже на то, что некоторые версии g ++ не допускают такую ​​инициализацию? или это вообще не разрешено?
Чайтанья
3
@Chaitanya: C ++ 11 Нестатические инициализаторы членов реализованы из gcc 4.7.
Джесси Гуд
@MarkGarcia, почему намного лучше? это может быть по требованию, если const memberдолжно быть доступно из функций / объектов, тогда почему статическое?
Асиф Муштак
Хотя обычно приводить пример новичкам в статике - это заблуждение. Потому что они могут не знать, что это только один для всех экземпляров (объектов) этого класса.
Мухамед Чичак
30

Есть несколько способов инициализировать члены const внутри класса.

Определение константного члена в целом также требует инициализации переменной.

1) Внутри класса, если вы хотите инициализировать константу, синтаксис выглядит следующим образом

static const int a = 10; //at declaration

2) Второй способ может быть

class A
{
  static const int a; //declaration
};

const int A::a = 10; //defining the static member outside the class

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

class A
{
  const int b;
  A(int c) : b(c) {} //const member initialized in initialization list
};
ravs2627
источник
8
Думаю, этот ответ требует пояснения. Использование ключевого слова static для члена класса не добавляет произвольного синтаксиса, чтобы сделать компилятор счастливым. Это означает, что существует одна копия переменной для всех экземпляров объекта, постоянных или нет. Это выбор дизайна, который необходимо тщательно продумать. В дальнейшем программист может решить, что этот постоянный член класса по-прежнему может изменяться для разных объектов, несмотря на то, что он остается постоянным на протяжении всего времени существования данного объекта.
опетренко
Согласовано .. Когда мы используем статический, он создает только одну его копию для всех объектов .. Как вы упомянули, это выбор дизайна. В случае единого экземпляра для всех объектов 1 и 2 должны работать. В случае индивидуальной копии для каждого объекта, 3 будут работать
ravs2627 04
Этот ответ предполагает простое изменение синтаксиса без последствий, тогда как изменение его на статичность - нет.
Исаак Вудс,
что, если вам нужно использовать double или float - это часть стандарта C ++ 11?
serup
14

Если вы не хотите, чтобы constчлен данных в классе был статическим, вы можете инициализировать constчлен данных с помощью конструктора класса. Например:

class Example{
      const int x;
    public:
      Example(int n);
};

Example::Example(int n):x(n){
}

если constв классе несколько членов данных, вы можете использовать следующий синтаксис для инициализации членов:

Example::Example(int n, int z):x(n),someOtherConstVariable(z){}
ГАНЕШ БК
источник
3
Я думаю, что это лучший ответ, чем тот, который был принят ....
Ян
1
Спасибо за кристально чистые примеры и вариант, показывающий множество! Устранена двусмысленность и лишнее исследование / прокрутка со стороны читателя!
clearlight
13
  1. Вы можете обновить свой компилятор для поддержки C ++ 11, и ваш код будет работать отлично.

  2. Используйте список инициализации в конструкторе.

    T1() : t( 100 )
    {
    }
Борисбн
источник
6

Другое решение

class T1
{
    enum
    {
        t = 100
    };

    public:
    T1();
};

Таким образом, t инициализируется значением 100, не может быть изменен и является частным.

Мускусный
источник
3

Если член является массивом, он будет немного сложнее, чем обычно:

class C
{
    static const int ARRAY[10];
 public:
    C() {}
};
const unsigned int C::ARRAY[10] = {0,1,2,3,4,5,6,7,8,9};

или

int* a = new int[N];
// fill a

class C {
  const std::vector<int> v;
public:
  C():v(a, a+N) {}
};
Вьет Ань До
источник
2

Другой возможный способ - это пространства имен:

#include <iostream>

namespace mySpace {
   static const int T = 100; 
}

using namespace std;

class T1
{
   public:
   T1()
   {
       cout << "T1 constructor: " << mySpace::T << endl;
   }
};

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

Баран
источник
1

Это правильный путь. Вы можете попробовать этот код.

#include <iostream>

using namespace std;

class T1 {
    const int t;

    public:
        T1():t(100) {
            cout << "T1 constructor: " << t << endl;
        }
};

int main() {
    T1 obj;
    return 0;
}

если вы используете, C++10 Compiler or belowвы не можете инициализировать член cons во время объявления. Итак, здесь необходимо создать конструктор для инициализации элемента данных const. Также необходимо использовать список инициализаторов, T1():t(100)чтобы мгновенно получить память.

Игрок Азиз
источник
0

вы можете добавить, staticчтобы сделать возможной инициализацию этой переменной-члена класса.

static const int i = 100;

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

dhokar.w
источник