web-dev-qa-db-ja.com

フィールドとコンストラクターパラメーターに同じ名前を使用できますか?


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

それは合法ですか?

55

はい、それは合法であり、すべてのプラットフォームで機能します。メンバー変数aを、渡された値aに正しく初期化します。

ただし、すべてではありませんが、別の名前を付ける方がよりクリーンであると考えられています。私は個人的にそれを実際にたくさん使っています:)

初期化リスト内の初期化項目の構文は次のとおりであるため、同じ変数名の初期化リストが機能します。

<メンバー>(<値>)

これを実行する簡単なプログラムを作成することで、上で書いた内容を確認できます(コンパイルされません)。

class  A
{

   A(int a)
   : a(5)//<--- try to initialize a non member variable to 5
   {
   }
};

次のようなコンパイルエラーが発生します。Aには「a」という名前のフィールドがありません。


余談ですが:

したくないかもしれませんがパラメーター名と同じメンバー名を使用する理由の1つは、次の傾向がより強くなるためです。

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):

必要な場合がありますパラメーター名と同じメンバー名を使用する理由の1つは、次のような傾向が少ないことです。

class  A
{

   A(int myVariable_)
   {
     //<-- do something with _myVariable, oops _myVariable wasn't initialized yet
     ...
     _myVariable = myVariable_;
   }
   int _myVariable;
};

これは、大規模な初期化リストでも発生する可能性があり、初期化リストで初期化する前に_myVariableを使用します。

50
Brian R. Bondy

このトピックに関して混乱を招く可能性があることの1つは、コンパイラーが変数に優先順位を付ける方法です。たとえば、コンストラクター引数の1つがクラスメンバーと同じ名前である場合、初期化リストに次のように記述できます。

MyClass(int a) : a(a)
{
}

しかし、上記のコードはこれと同じ効果がありますか?

MyClass(int a)
{
    a=a;
}

答えはノーです。コンストラクターの本体内に「a」と入力すると、コンパイラーは最初に「a」というローカル変数またはコンストラクター引数を検索し、見つからない場合にのみ「a」というクラスメンバーの検索を開始します。 (そして、何も利用できない場合は、「a」と呼ばれるグローバル変数を探します)。その結果、上記のステートメント「a = a」は、引数「a」に格納されている値を引数「a」に割り当て、それを役に立たないステートメントにします。

引数の値をクラスメンバー「a」に割り当てるには、thisクラスインスタンス内の値を参照していることをコンパイラに通知する必要があります。

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"
{
}
20
Dragonion

仮パラメーターとメンバーの名前が同じである場合は、コンストラクター内でこのポインターを使用してメンバー変数を使用することに注意してください。

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

法務:はい、ブライアンが説明したように、コンパイラーは、初期化子リストで予期される名前がメンバー(または基本クラス)でなければならず、他のものではないことを知っています。

良いスタイル:おそらくそうではない-多くのプログラマー(あなたを含む)にとって、結果は明白ではありません。パラメータに別の名前を使用すると、コードが合法であると同時に、優れたスタイルになります。

私はいくつかを書くことを好みます:

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


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

この方法の問題は、合法であるかもしれませんが、コンパイラが-Wshadowが使用されたときにシャドウされた変数を考慮し、他のコードでそれらの警告を難読化することです。

さらに、重要なコンストラクターでは、これをメンバー名の前に置くのを忘れて、間違いを犯します。

Javaでもこれは許可されていません。これは悪い習慣であり、避けるべきです。

2
Rick