Попытка инициализировать элемент данных в конструкторе, но это не удается. Зачем?
Переменные-члены указателя структуры возвращают неправильное число.
Вот объявление структуры:
struct Obj {
int val;
Obj(int val) { val = val; }
};
Вот где это становится забавным:
Obj* cool = new Obj(4);
cout << cool->val; // outputs a number that's not 4
cout << (cool->val == 4); // prints 0... interesting
2 ответа
Почему я получаю эти странные цифры?
Вы никогда не инициализируете Obj::val
таким образом, значение - это то, что происходит в этой ячейке памяти в момент создания экземпляра Obj
,
ПРИЧИНА: Имена играют в прятки
struct Obj {
int val; // (A)
Obj(int val) { // (C)
val = val; // (B)
}
};
Внутри конструктора Obj
названный параметр val
скрывает элемент данных с именем val
; другими словами, вы присваиваете значение аргумента с именем val
к аргументу по имени val
,
Стандарт гласит, что переменная, объявленная в более узкой области видимости, чем предыдущая, будет эффективно скрывать старую.
Это означает, что, поскольку аргумент val
at (B) находится в более узкой области, чем (A), в точке (C) компилятор считает, что вы ссылаетесь на аргумент.
Предлагаемые решения
У вас есть несколько вариантов решения этой проблемы
this->val = val; // (A)
Obj::val = val; // equivalent
Obj (int val) : val (val) { } // (B)
Obj (int foo) { val = foo; } // (C)
А) использовать
this->val
явно указать, что вы хотите присвоить значение элементу данных ObjБ), используйте mem-инициализатор где
Obj::val
не будет скрыто по имени аргументаВ) измените название своего аргумента
Mem-инициализатор выглядит жутким, почему он включен?
Из предложенных решений решение, помеченное (B), является предпочтительным.
Он вызывается с использованием mem-initializer и инициализирует член val значением аргумента val непосредственно после вызова конструктора; вместо этого сначала необходимо инициализировать по умолчанию, а затем присвоить значение.
Рекомендуется также не иметь аргументов с тем же именем, что и переменные-члены, так как это может быть подвержено ошибкам, если забыть о сокрытии имени.
Обычный дизайн состоит в том, чтобы префикс каждого члена данных m_
явно указать, что таковой действительно является элемент экземпляра, например, в следующем фрагменте:
struct Obj {
Obj(int val) : m_val (val) { }
int m_val;
};
Это:
Obj(int val) { val = val; }
просто присваивает параметр себе и оставляет переменную-член, содержащую мусор. Тебе нужно:
Obj(int val) : val(val) {}
или (если вам действительно нужно назначить, а не инициализировать):
Obj(int val) { this->val = val; }
или же:
Obj(int the_val) { val = the_val; }
Вы можете рассмотреть возможность использования соглашения об именах для членов:
int m_val;
Obj(int val) : m_val(val) {}