class C {
T a;
public:
C(T a): a(a) {;}
};
Это законно?
Просто пустое заявление, не повредит, обещаю :)
Просто потому, что это законно, еще не значит, что это правильно; )





Да, это законно и работает на всех платформах. Он правильно инициализирует вашу переменную-член a переданным значением a.
Некоторые более чистые считают, что называть их по-другому, но не все. Я лично очень часто им пользуюсь :)
Списки инициализации с тем же именем переменной работают, потому что синтаксис элемента инициализации в списке инициализации следующий:
<член> (<значение>)
Вы можете проверить то, что я написал выше, создав простую программу, которая делает это: (Она не будет компилироваться)
class A
{
A(int a)
: a(5)//<--- try to initialize a non member variable to 5
{
}
};
Вы получите ошибку компиляции, например: A не имеет поля с именем 'a'.
На стороне примечания:
Одна из причин, по которой вы может не хотеть используете то же имя элемента, что и имя параметра, заключается в том, что вы более склонны к следующему:
class A
{
A(int myVarriable)
: myVariable(myVariable)//<--- Bug, there was a typo in the parameter name, myVariable will never be initialized properly
{
}
int myVariable;
};
В примечании (2):
Одна из причин, по которой вы может захотеть используете то же имя элемента, что и имя параметра, заключается в том, что вы менее подвержены следующему:
class A
{
A(int myVariable_)
{
//<-- do something with _myVariable, oops _myVariable wasn't initialized yet
...
_myVariable = myVariable_;
}
int _myVariable;
};
Это также может произойти с большими списками инициализации, и вы используете _myVariable перед его инициализацией в списке инициализации.
Дело вкуса. Я предпочитаю давать одинаковые имена одинаковым вещам. Вот почему я широко использую пространства имен.
Очень часто для приватных полей можно встретить такие названия, как «a_» или «_a».
Переменные-члены часто бывают m_a или а. Переменные с ограниченным объемом часто являются.
Недавно я тоже переключился на использование этой техники (и устранение неоднозначности с помощью this-> в телах методов). Это мой предпочтительный способ в C#, и, вернувшись к C++, я отказался от своей старой практики использования префикса m_ для переменных-членов. Теперь намного лучше (YMMV)
о побочном примечании первое: компилятор сообщит мне о неиспользуемом параметре.
иногда в проектах предупреждения теряются, хотя из-за установленного уровня предупреждений или из-за сторонних включений, которые вы не можете исправить.
Я всегда устанавливаю максимальный уровень предупреждения. Чтобы справиться с некорректным поведением сторонних заголовков, можно использовать «#pragama warning» с опцией «подавить» или «отключить» и «по умолчанию». Это для Visual C++.
@ BrianR.Bondy сторонние включения можно отключить, пометив их путь system, как для gcc -isystem /some/path вместо обычного -I/some/path.
Законно: да, как объяснил Брайан, компилятор знает, что имя, ожидаемое в списке инициализаторов, должно быть членом (или базовым классом), а не чем-либо еще.
Хороший стиль: скорее всего, нет - для многих программистов (включая вас, кажется) результат неочевиден. Использование другого имени для параметра сохранит законность кода и в то же время сделает его хорошим стилем.
Я бы предпочел написать что-нибудь из:
class C {
T a_;
public:
C(T a): a_(a) {}
};
class C {
T a;
public:
C(T value): a(value) {}
};
Нет, для меня результат очевиден. если конструкция (а) допустима, то это определенно означает, что эти «а» разные. Я просто не был уверен, действительно ли это законно на C++.
Вам нужно быть очень осторожным при использовании идентификаторов с ведущими символами подчеркивания, чтобы избежать конфликтов с реализацией. На самом деле все в порядке, когда за ним следует символ в нижнем регистре, как здесь, но широко считается, что лучше всего их избегать. См. Вопрос 228783 для получения дополнительной информации.
Это вопрос предпочтений, есть преимущества в обоих направлениях.
@SergeySkoblikov, это не так очевидно: a=a тоже легален, но это не значит, что LHS и RHS имеют разное значение.
если формальный параметр и член названы одинаково, остерегайтесь использования этого указателя внутри конструктора для использования переменной-члена
class C {
T a;
public:
C(T a): a(a) {
this->a.sort ;//correct
a.sort();//will not affect the actual member variable
}
};
Хм ... похоже, отличный повод назвать их по-другому. Хорошая точка зрения.
Это хорошая причина использовать const для неизменности параметров ввода по значению в реализациях функций.
Одна из вещей, которая может ввести в заблуждение относительно этой темы, - это то, как компилятор определяет приоритеты переменных. Например, если один из аргументов конструктора имеет то же имя, что и член класса, вы можете написать следующее в списке инициализации:
MyClass(int a) : a(a)
{
}
Но имеет ли приведенный выше код такой же эффект?
MyClass(int a)
{
a=a;
}
Ответ - нет. Каждый раз, когда вы вводите «a» внутри тела конструктора, компилятор сначала будет искать локальную переменную или аргумент конструктора с именем «a», и только если он не найдет его, он начнет поиск члена класса с именем «a». (и, если его нет, он, кстати, будет искать глобальную переменную с именем "a"). В результате приведенный выше статус «a = a» присваивает значение, хранящееся в аргументе «a», аргументу «a», делая его бесполезным оператором.
Чтобы присвоить значение аргумента члену класса «a», вам необходимо сообщить компилятору, что вы ссылаетесь на значение внутри экземпляра класса это:
MyClass(int a)
{
this->a=a;
}
Хорошо, но что, если бы вы сделали что-то подобное (обратите внимание, что аргумента с именем «а» нет):
MyClass() : a(a)
{
}
Что ж, в этом случае компилятор сначала будет искать аргумент с именем «a», и когда он обнаружит, что его нет, он присвоит значение члена класса «a» члену класса «a», который фактически ничего не сделает. .
Наконец, вы должны знать, что вы можете присваивать значения только членам класса в списке инициализации, поэтому следующее приведет к ошибке:
MyClass(int x) : x(100) // error: the class doesn't have a member called "x"
{
}
Проблема с этой практикой, хотя она может быть законной, заключается в том, что компиляторы будут считать переменные затененными при использовании -Wshadow и затемнить эти предупреждения в другом коде.
Более того, в нетривиальном конструкторе вы совершаете ошибку, забывая поставить this-> перед именем члена.
Java даже этого не позволяет. Это плохая практика, и ее следует избегать.
Java позволяет использовать это, чтобы различать параметр и поле: this.a = a;
Что с этим ';' ?!?