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' という名前のフィールドがありません。
余談ですが:
パラメーター名と同じメンバー名を使用したくない理由の 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 を使用します。
このトピックに関して混乱を招く可能性があることの 1 つは、コンパイラによる変数の優先順位付けです。たとえば、コンストラクター引数の 1 つがクラス メンバーと同じ名前を持つ場合、初期化リストに次のように記述できます。
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
}
};
法務:はい、ブライアンが説明したように、コンパイラーは、初期化子リストで予期される名前がメンバー(または基本クラス)でなければならず、他のものではないことを知っています。
良いスタイル:おそらくそうではありません-多くのプログラマー(あなたを含む)にとって、結果は明らかではありません。パラメータに別の名前を使用すると、コードが正当に保たれ、同時に優れたスタイルになります。
私はいくつかを書くことを好みます:
class C {
T a_;
public:
C(T a): a_(a) {}
};
class C {
T a;
public:
C(T value): a(value) {}
};
この慣行の問題点は、正当かもしれませんが、 -Wshadow が使用されたときにコンパイラが変数をシャドウと見なし、他のコードでそれらの警告を難読化することです。
さらに、重要なコンストラクターでは、メンバー名の前に this-> を付けるのを忘れて、間違いを犯します。
Java はこれを許可しません。これは悪い習慣であり、避けるべきです。