Могу ли я использовать одинаковые имена для полей и параметров конструктора? - PullRequest
53 голосов
/ 06 ноября 2008

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

Это законно?

Ответы [ 5 ]

50 голосов
/ 06 ноября 2008

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

19 голосов
/ 12 октября 2011

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

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"
{
}
9 голосов
/ 07 ноября 2008

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

class C {
  T a;
public:
  C(T a): a(a) {
this->a.sort ;//correct
a.sort();//will not affect the actual member variable
}
};
4 голосов
/ 06 ноября 2008

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

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

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

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


class C {
 T a;
 public:
 C(T value): a(value) {}
};
2 голосов
/ 19 марта 2014

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

Более того, в нетривиальном конструкторе вы допускаете ошибку, забывая поставить this-> перед именем члена.

Java даже не позволяет этого. Это плохая практика, и ее следует избегать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...