167

C#、C++、および Java では、パラメーターを受け取るコンストラクターを作成すると、デフォルトのパラメーターなしのコンストラクターがなくなります。私はいつもこの事実を受け入れてきましたが、今ではなぜだろうと考え始めました.

この動作の理由は何ですか? 「独自のコンストラクターを作成した場合、おそらくこの暗黙的なコンストラクターをぶらぶらさせたくない」という「安全対策/推測」ですか? それとも、自分でコンストラクターを作成すると、コンパイラーがコンストラクターを追加できないという技術的な理由がありますか?

4

11 に答える 11

224

独自のコンストラクターを追加した場合、コンパイラーがコンストラクターを追加できなかったという理由はありません。コンパイラーは、必要なことはほとんど何でも実行できます。ただし、最も理にかなっているものを確認する必要があります。

  • 非静的クラスのコンストラクターを定義ていない場合は、おそらくそのクラスをインスタンス化できるようにしたいと考えています。それを可能にするために、コンパイラーはパラメーターなしのコンストラクターを追加する必要があります。これは効果がなく、インスタンス化を許可します。これは、コードを機能させるためだけに空のコンストラクターをコードに含める必要がないことを意味します。
  • 独自のコンストラクター、特にパラメーターを持つコンストラクターを定義した場合、クラスの作成時に実行する必要がある独自のロジックがある可能性が高くなります。この場合、コンパイラが空のパラメーターなしのコンストラクターを作成すると、誰かが私が書いたロジックをスキップできるようになり、さまざまな方法でコードが壊れる可能性があります。この場合、デフォルトの空のコンストラクターが必要な場合は、明示的に指定する必要があります。

したがって、いずれの場合も、コードの意図を維持するという点で、現在のコンパイラの動作が最も理にかなっていることがわかります。

于 2012-08-03T08:43:15.447 に答える
20

編集。実際、最初の回答で言ったことは有効ですが、これが本当の理由です。

最初に C がありました。C はオブジェクト指向ではありません (オブジェクト指向のアプローチを取ることはできますが、それは役に立たず、何も強制しません)。

その後、C With Classes があり、後に C++ と改名されました。C++ はオブジェクト指向であるため、カプセル化を促進し、オブジェクトの不変条件 (構築時およびメソッドの開始時と終了時にオブジェクトが有効な状態であること) を保証します。

これを行う自然なことは、クラスが有効な状態で開始することを保証するために常にコンストラクターを持たなければならないことを強制することです - コンストラクターがこれを保証するために何もする必要がない場合、空のコンストラクターはこの事実を文書化します.

しかし、C++ での目標は、可能な限りすべての有効な C プログラムが有効な C++ プログラムでもあるという点まで C と互換性を持つことでした (もはや目標としては積極的ではなく、C が C++ から分離して進化したことは、もはやそれが成り立たないことを意味します)。 )。

この影響の 1 つは、 と の間で機能が重複していることstructですclass。前者は C のやり方 (デフォルトではすべて公開) を行い、後者は優れた OO の方法 (デフォルトではすべて非公開、開発者は公開したいものを積極的に公開する) で物事を行います。

もう 1 つのstruct理由は、C にはコンストラクターがないためにコンストラクターを持てなかった C が C++ で有効であるためには、C++ の見方に対してこれに意味がなければならないということです。そのため、コンストラクターを持たないことは不変条件を積極的に確保するという OO の実践に反しますが、C++ はこれを、空の本体があるかのように動作するデフォルトのパラメーターなしのコンストラクターが存在することを意味すると解釈しました。

すべての Cstructsは有効な C++structsになりました (つまり、C++ と同じで、classesメンバーと継承 - パブリックのすべてが含まれます)、パラメーターのない単一のコンストラクターがあるかのように外側から扱われます。

classただし、またはにコンストラクターを配置した場合はstruct、C の方法ではなく C++/OO の方法で処理を行うことになり、既定のコンストラクターは必要ありません。

それは省略形として機能したため、他の方法では互換性が不可能な場合でも、人々はそれを使い続けました (C にはない他の C++ 機能を使用していました)。

したがって、Java (多くの点で C++ に基づく) が登場し、その後 C# (さまざまな点で C++ と Java に基づく) が登場したとき、彼らはこのアプローチを、コーダーが既に慣れているものとして維持しました。

Stroustrup はこれについて彼の The C++ Programming Languageで書いており、 The Design and Evolution of C++ では言語の「理由」にもっと焦点を当てています。

=== 元の回答 ===

これは起こらなかったとしましょう。

パラメーターなしのコンストラクターが必要ないとしましょう。コンストラクターがないとクラスを意味のある状態にすることができないからです。実際、これは C# で発生する可能性があるものですstruct(ただし、C# ですべてゼロと NULL を意味のある方法で使用できないstruct場合は、せいぜい非公開の最適化を使用しているだけであり、それ以外の場合は、使用上の設計上の欠陥struct)。

クラスがその不変条件を保護できるようにするには、特別なremoveDefaultConstructorキーワードが必要です。少なくとも、呼び出しコードがデフォルトを呼び出さないようにするために、パラメーターなしのプライベート コンストラクターを作成する必要があります。

これにより、言語がさらに複雑になります。やらないほうがいい。

全体として、コンストラクターを追加することをデフォルトを削除するものと考えないでください。何もしないパラメーターなしのコンストラクターを追加するためのシンタックス シュガーとして、コンストラクターをまったく持たないことを考えたほうがよいでしょう。

于 2012-08-03T15:48:23.623 に答える
3

これはコンパイラの便利な機能です。パラメーターを使用してコンストラクターを定義するが、パラメーターなしのコンストラクターを定義しない場合、パラメーターなしのコンストラクターを許可したくない可能性がはるかに高くなります。

これは、空のコンストラクターで初期化しても意味がない多くのオブジェクトの場合です。

それ以外の場合は、制限するクラスごとにプライベートパラメーターなしコンストラクターを宣言する必要があります。

私の意見では、パラメーターが機能する必要があるクラスのパラメーターなしのコンストラクターを許可するのは良いスタイルではありません。

于 2012-08-03T08:45:21.617 に答える
3

質問は逆であるべきだと思います.他のコンストラクターを定義していないのに、なぜデフォルトのコンストラクターを宣言する必要がないのですか?

非静的クラスにはコンストラクターが必須です。
したがって、コンストラクターを定義していない場合、生成されたデフォルトのコンストラクターは C# コンパイラの便利な機能にすぎず、コンストラクターがないとクラスは有効ではないと思います。したがって、何もしないコンストラクターを暗黙的に生成しても問題はありません。空のコンストラクターがあちこちにあるよりも確かにきれいに見えます。

コンストラクターを既に定義している場合、クラスは有効ですが、なぜコンパイラーはデフォルトのコンストラクターが必要であると想定するのでしょうか? 欲しくない場合はどうしますか?そのデフォルトのコンストラクターを生成しないようにコンパイラーに指示する属性を実装しますか? それは良い考えだとは思いません。

于 2012-08-03T08:44:42.200 に答える
1

デフォルトのコンストラクターは、クラスにコンストラクターがない場合にのみ構築できます。コンパイラは、これをバックアップ メカニズムとしてのみ提供するように記述されています。

パラメーター化されたコンストラクターがある場合、既定のコンストラクターを使用してオブジェクトを作成したくない場合があります。コンパイラがデフォルトのコンストラクターを提供していた場合、引数なしのコンストラクターを記述してプライベートにし、引数なしでオブジェクトが作成されるのを防ぐ必要がありました。

また、無効にすることを忘れたり、デフォルトのコンストラクターを「プライベート化」したりする可能性が高くなり、潜在的な機能エラーが発生する可能性が高くなります。

そして、デフォルトの方法で、またはパラメータを渡すことによってオブジェクトを作成したい場合は、引数なしのコンストラクタを明示的に定義する必要があります。これは厳密にチェックされ、それ以外の場合はコンパイラがエラーを出すため、抜け穴はありません。

于 2012-08-03T20:11:32.700 に答える
1

これはコンパイラによって処理されると思います。.netでアセンブリを開くILDASMと、コードに含まれていなくても、既定のコンストラクターが表示されます。パラメーター化されたコンストラクターを定義すると、デフォルトのコンストラクターは表示されません。

実際にクラス (非静的) を定義すると、コンパイラはインスタンスを作成するだけであると考えてこの機能を提供します。また、特定の操作を実行したい場合は、必ず独自のコンストラクターを用意する必要があります。

于 2012-08-27T17:38:56.430 に答える
1

前提

この動作は、クラスが既定のパブリック パラメーターなしのコンストラクターを持つという決定の自然な拡張と見なすことができます。尋ねられた質問に基づいて、この決定を前提として取り、この場合は質問していないと仮定します。

デフォルトのコンストラクターを削除する方法

したがって、既定のパブリック パラメーターなしのコンストラクターを削除する方法が必要です。この削除は、次の方法で実行できます。

  1. 非パブリックのパラメーターなしのコンストラクターを宣言する
  2. パラメーターを持つコンストラクターが宣言されている場合、パラメーターなしのコンストラクターを自動的に削除します
  3. パラメーターなしのコンストラクターを削除するようにコンパイラーに指示するためのキーワード/属性 (簡単に除外できるほど厄介です)

最適なソリューションの選択

ここで、次のことを自問します:パラメーターなしのコンストラクターがない場合、何に置き換える必要がありますか? デフォルトのパブリック パラメーターなしコンストラクターを削除する必要があるのは、どのような種類のシナリオですか?

物事がうまくいき始めます。まず、パラメーターを持つコンストラクターまたは非パブリック コンストラクターに置き換える必要があります。次に、パラメーターなしのコンストラクターが必要ないシナリオは次のとおりです。

  1. クラスをまったくインスタンス化したくない、またはコンストラクターの可視性を制御したい:非公開コンストラクターを宣言する
  2. 構築時にパラメータを強制的に提供したい:コンストラクタをパラメータで宣言する

結論

これで、C#、C++、および Java でデフォルトのパブリック パラメーターなしコンストラクターを削除できるようになった 2 つの方法がまさにこれです。

于 2012-08-25T23:59:15.863 に答える
0

これは、コンストラクターを定義しないと、コンパイラーが引数を取らないコンストラクターを自動的に生成するためです。コンストラクターからさらに何かが必要な場合は、それをオーバーライドします。これは関数のオーバーロードではありません。したがって、コンパイラが現在認識している唯一のコンストラクタは、引数を取るコンストラクタです。この問題に対処するために、コンストラクターが値なしで渡された場合にデフォルト値を渡すことができます。

于 2012-08-26T05:35:58.780 に答える