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



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

законно ли это?

5 51

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 перед инициализацией его в списке инициализации.

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

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;
}

отлично, но что делать, если вы сделали что-то вроде этого (обратите внимание, что нет аргумента под названием "a"):

MyClass() : a(a)
{
}

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

вы должны знать, что вы можете только присвойте значения членам класса в списке инициализации, чтобы следующее привело к ошибке:
MyClass(int x) : x(100) // error: the class doesn't have a member called "x"
{
}

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

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

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

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

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

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


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

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

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

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