Почему переменная const, объявленная как член класса, все еще может быть изменена?

Если переменная const, которая была назначена, все еще может быть переназначена, то это не const? Взять, к примеру:

 struct ss
 {
     const int m = 1024;

     ss()
     {
     }

     ss(int m) : m(m)
     {
     }
 };



ss sa;
ss sb(-1);

cout << sa.m << endl;
cout << sb.m << endl; 

Ничего себе, м не является постоянным в конце концов!

> /* Ouput:
> 
> 1024
> -1
> 
> */

2 ответа

 ss(int m) : m(m)
 {
 }

Это говорит о том, что когда класс ss инициализирован, его член m инициализируется с помощью параметра m, Член m на самом деле не может быть изменено, но оно может быть инициализировано, как и любой другой const объект. Обратите внимание, что если бы мы сделали вместо

 ss(int m)
 {
     this->m = m;
 }

тогда у нас будет проблема, так как ss::m должен быть инициализирован. И если ss::m был класс с конструктором по умолчанию, то в

 ss(FooClass m)
 {
     this->m = m;
 }

нормально не инициализировать ss::m явно (так как это будет просто построено по умолчанию), но строка в теле конструктора будет отклонена, так как это изменит ss::m после того, как он уже был инициализирован.

Изменить: Ой, я не понял ваш первоначальный вопрос.

Инициализатор фигурной или равной скобки, такой как

const int m = 1024;

используется только если член не указан в инициализаторе ctor. Другими словами, поскольку конструктор по умолчанию явно не инициализируется mиспользуется значение 1024. Но ss::ss(int) действительно инициализирует m, так что инициализатор скобки или равный игнорируется.

Ваш пример имеет дело только с различными режимами инициализации, переназначение здесь не происходит. То, что вы видите, это эффект того, что список инициализаторов конструкторов предпочтительнее, чем инициализатор членов класса in, это видно из черновика стандартного раздела C++. 12.6.2 Инициализация баз и членов параграфа 9, в котором говорится:

Если данный элемент нестатических данных имеет инициализатор скобок или равных и инициализатор mem, выполняется инициализация, заданная инициализатором mem, и инициализатор скобок или равных равен: игнорируются. [Пример: дано

struct A {
int i = / some integer expression with side effects / ;
A(int arg) : i(arg) { }
// ...
};

конструктор A(int) просто инициализирует i значением arg, и побочные эффекты в инициализаторе i brace-orequal не будут иметь места. - конец примера]

Как уже обсуждалось в статье: Является ли новая функция инициализации члена C++11 при объявлении устаревшими списками инициализации? Это полезная функция, поскольку она позволяет вам задавать переменные-члены по умолчанию, а затем переопределять эти значения по умолчанию на основе вызываемого конструктора.

Другие вопросы по тегам