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


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
};

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;

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.