Могу ли я использовать одинаковые имена для полей и параметров конструктора?


class C {
  T a;
public:
  C(T a): a(a) {;}
};

Это законно?

Что с этим ';' ?!?

Terminus 06.11.2008 16:57

Просто пустое заявление, не повредит, обещаю :)

Brian R. Bondy 06.11.2008 17:05

Просто потому, что это законно, еще не значит, что это правильно; )

Adam Erickson 13.06.2018 06:19
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
68
3
24 363
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

Да, это законно и работает на всех платформах. Он правильно инициализирует вашу переменную-член 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 перед его инициализацией в списке инициализации.

Дело вкуса. Я предпочитаю давать одинаковые имена одинаковым вещам. Вот почему я широко использую пространства имен.

Sergey Skoblikov 06.11.2008 16:01

Очень часто для приватных полей можно встретить такие названия, как «a_» или «_a».

Marcin Gil 06.11.2008 16:06

Переменные-члены часто бывают m_a или а. Переменные с ограниченным объемом часто являются.

Brian R. Bondy 06.11.2008 16:12

Недавно я тоже переключился на использование этой техники (и устранение неоднозначности с помощью this-> в телах методов). Это мой предпочтительный способ в C#, и, вернувшись к C++, я отказался от своей старой практики использования префикса m_ для переменных-членов. Теперь намного лучше (YMMV)

philsquared 06.11.2008 16:28

о побочном примечании первое: компилятор сообщит мне о неиспользуемом параметре.

Sergey Skoblikov 06.11.2008 18:20

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

Brian R. Bondy 06.11.2008 21:12

Я всегда устанавливаю максимальный уровень предупреждения. Чтобы справиться с некорректным поведением сторонних заголовков, можно использовать «#pragama warning» с опцией «подавить» или «отключить» и «по умолчанию». Это для Visual C++.

Sergey Skoblikov 07.11.2008 00:40

@ BrianR.Bondy сторонние включения можно отключить, пометив их путь system, как для gcc -isystem /some/path вместо обычного -I/some/path.

Ruslan 10.01.2016 14:27

Законно: да, как объяснил Брайан, компилятор знает, что имя, ожидаемое в списке инициализаторов, должно быть членом (или базовым классом), а не чем-либо еще.

Хороший стиль: скорее всего, нет - для многих программистов (включая вас, кажется) результат неочевиден. Использование другого имени для параметра сохранит законность кода и в то же время сделает его хорошим стилем.

Я бы предпочел написать что-нибудь из:

class C {
  T a_;
public:
  C(T a): a_(a) {}
};


class C {
 T a;
 public:
 C(T value): a(value) {}
};

Нет, для меня результат очевиден. если конструкция (а) допустима, то это определенно означает, что эти «а» разные. Я просто не был уверен, действительно ли это законно на C++.

Sergey Skoblikov 06.11.2008 16:42

Вам нужно быть очень осторожным при использовании идентификаторов с ведущими символами подчеркивания, чтобы избежать конфликтов с реализацией. На самом деле все в порядке, когда за ним следует символ в нижнем регистре, как здесь, но широко считается, что лучше всего их избегать. См. Вопрос 228783 для получения дополнительной информации.

tragomaskhalos 06.11.2008 16:45

Это вопрос предпочтений, есть преимущества в обоих направлениях.

Brian R. Bondy 06.11.2008 17:05

@SergeySkoblikov, это не так очевидно: a=a тоже легален, но это не значит, что LHS и RHS имеют разное значение.

Ruslan 10.01.2016 14:30

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

class C {
  T a;
public:
  C(T a): a(a) {
this->a.sort ;//correct
a.sort();//will not affect the actual member variable
}
};

Хм ... похоже, отличный повод назвать их по-другому. Хорошая точка зрения.

Onorio Catenacci 07.11.2008 18:43

Это хорошая причина использовать const для неизменности параметров ввода по значению в реализациях функций.

Ruslan 10.01.2016 14:28

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

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;

Audrius Meskauskas 10.07.2018 11:51

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