57

C++ では、コンストラクターの実行を開始する前に、初期化子リストを使用してクラスのフィールドを初期化できます。例えば:

Foo::Foo(string s, double d, int n) : name(s), weight(d), age(n) {
    // Empty; already handled!
}

Java に同様の機能がない理由が気になります。Core Java: Volume 1によると:

C++ は、この特殊な構文を使用してフィールド コンストラクターを呼び出します。Java では、オブジェクトにはサブオブジェクトがなく、他のオブジェクトへのポインタしかないため、その必要はありません。

ここに私の質問があります:

  1. 「オブジェクトにはサブオブジェクトがないため」とはどういう意味ですか? サブオブジェクトが何かわかりません (調べてみました)。スーパークラスを拡張するサブクラスのインスタンス化を意味しますか?

  2. Java に C++ のようなイニシャライザ リストがない理由については、Java ではすべてのフィールドがデフォルトですでに初期化されているため、また Java がsuperキーワードを使用してスーパー (または C++ 用語ではベース) クラス コンストラクタを呼び出すためであると考えられます。 . これは正しいです?

4

3 に答える 3

104

C++ では、Java には存在しないか、Java では異なる動作をするいくつかの言語機能があるため、初期化子リストが必要です。

  1. constconst: C++ では、割り当てられず、初期化子リストで初期化する必要があるとマークされているフィールドを定義できます。Java にはフィールドがありますが、コンストラクターの本体でフィールドにfinal割り当てることができます。finalC++ では、constコンストラクター内のフィールドへの代入は不正です。

  2. 参照: C++ では、参照 (ポインターではなく) を初期化して、オブジェクトにバインドする必要があります。初期化子なしで参照を作成することは違法です。C++ では、最初に初期化せずにコンストラクターの本体で参照を参照すると、初期化されていない参照を使用することになるため、これを指定する方法は初期化子リストを使用します。Java では、オブジェクト参照は C++ ポインタのように動作し、作成後に割り当てることができます。それ以外の場合はデフォルトですnull

  3. 直接サブオブジェクト。C++ では、オブジェクトは直接フィールドとしてオブジェクトを含むことができますが、Java ではオブジェクトはそれらのオブジェクトへの参照のみを保持できます。つまり、C++ では、stringメンバーとして を持つオブジェクトを宣言すると、その文字列のストレージ スペースは、オブジェクト自体のスペースに直接組み込まれますが、Java では、他のオブジェクトへの参照用のスペースを取得するだけです。Stringオブジェクトは別の場所に保管されています。したがって、C++ はこれらのサブオブジェクトに初期値を与える方法を提供する必要があります。そうしないと、初期化されないままになるからです。デフォルトでは、これらの型に対してデフォルトのコンストラクターを使用しますが、別のコンストラクターを使用したい場合、またはデフォルトのコンストラクターを使用できない場合は、初期化子リストを使用してこれをバイパスできます。Java では、参照がデフォルトで に設定されるため、これについて心配する必要はありませんnull。実際に参照したいオブジェクトを参照するように割り当てることができます。デフォルト以外のコンストラクターを使用する場合、特別な構文は必要ありません。適切なコンストラクターを介して初期化された新しいオブジェクトへの参照を設定するだけです。

Java がイニシャライザ リストを必要とする少数のケース (たとえば、スーパークラス コンストラクタを呼び出したり、そのフィールドにデフォルト値を与えたりする場合) では、これは他の 2 つの言語機能によって処理されます。superスーパークラス コンストラクタを呼び出すキーワードと、Java オブジェクトがそれらが宣言された時点で、フィールドにデフォルト値を与えます。C++ には複数の継承があるため、単一のsuperキーワードを持つだけでは、単一の基本クラスを明確に参照することはできません。また、C++11 より前の C++ は、クラス内の既定の初期化子をサポートしておらず、初期化子リストに依存する必要がありました。

お役に立てれば!

于 2011-08-22T23:15:21.403 に答える
1

Java は、型がゼロ値を持たないフィールドの初期化を許可するためにそれらを必要としないためです。

C++ の場合

class C {
  D d;
}

のメンバー初期化子がないとdD::D()が呼び出され、 のゼロ型がない場合、フィールドを初期化できなくなりますD。これは、D::D()が明示的に宣言されている場合に発生する可能性がありprivateます。

Java では、すべての参照型に既知のゼロ値nullがあるため、フィールドは常に初期化できます。

Java は、すべてのfinalフィールドが最初に使用される前とコンストラクターが終了する前に確実に初期化されるようにするための一連の作業も行います。そのため、Java には C++ のconstフィールド初期化要件のような要件がありますが、this.fieldName = <expression>フィールドの初期化を意味するためにコンストラクター本体でオーバーロードするだけです。

  • : ctor でスローされたモジュロ例外、基本クラスからのオーバーライドされたメソッド呼び出しなど。
于 2011-08-22T23:13:25.337 に答える