web-dev-qa-db-ja.com

パラメータ付きのコンストラクタを作成すると、デフォルトのパラメータなしのコンストラクタがなくなるのはなぜですか

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

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

158
olagjo

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

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

そのため、それぞれのケースで、現在のコンパイラの動作は、コードの可能性が高いを保持するという点で最も意味があることがわかります。

220
Dan Puzey

言語がこのように設計されているの技術的な理由は確かにありません。

私が見ることができる4つのやや現実的なオプションがあります:

  1. デフォルトのコンストラクタはまったくありません
  2. 現在のシナリオ
  3. Alwaysデフォルトでデフォルトのコンストラクタを提供しますが、明示的に抑制することを許可します
  4. 常にデフォルトのコンストラクタを提供しwithout

オプション1はやや魅力的です。コードを多くすればするほど、reallyがパラメーターなしのコンストラクターを必要とする頻度が少なくなります。いつか、実際に実際にデフォルトコンストラクタを使用する頻度を数える必要があります...

オプション2私は大丈夫です。

オプション3は、残りの言語については、JavaとC#の両方のフローに逆行します。明示的に「削除」するものはありません。 Javaではデフォルトで。

オプション4は恐ろしいです-あなたは絶対に特定のパラメータで構築を強制できるようにしたいです。 new FileStream()はどういう意味ですか?

したがって、基本的に、ifデフォルトのコンストラクタを提供することは理にかなっているという前提を受け入れ、すぐにそれを抑制することは非常に理にかなっていると思います独自のコンストラクタを提供します。

69
Jon Skeet

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

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

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

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

しかし、C++の目標は、可能な限りすべての有効なCプログラムも有効なC++プログラムになるように、Cと互換性を持たせることでした(もはやアクティブな目標ではなく、CからC++への独立した進化により、C )。

これの1つの効果は、structclassの間の機能の重複でした。前者はCの方法(デフォルトではすべて公開)で、後者は適切なOOの方法(デフォルトでは非公開、開発者は公開したいものを積極的に公開します)で処理します)。

もう1つは、CにコンストラクターがないためC structがC++で有効になるために、C++で有効にするために、C++の方法に対してこの意味がある必要があることです。それを見て。したがって、コンストラクターがないと、OO不変式を積極的に確保するという慣習に反することになりますが、C++は、空の本体を持つように動作するデフォルトのパラメーターレスコンストラクターがあることを意味します。

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

ただし、classまたはstructにコンストラクターを配置した場合は、Cの方法ではなくC++/OOの方法で作業を行っていたため、デフォルトのコンストラクターは必要ありませんでした。

それは速記として機能したので、人々は互換性がそれ以外の方法で可能でなかったときでさえ、それを使い続けました(Cにない他のC++機能を使用しました)。

したがって、Javaが(C++に基づいてさまざまな方法で)登場し、その後C#(C++およびJavaに基づいてさまざまな方法で))、このアプローチを何かコーダーが既に慣れているかもしれません。

Stroustrupは、これについてC++プログラミング言語で書いており、さらに詳しくはC++の設計と進化の言語の「理由」に重点を置いています。

===元の回答===

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

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

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

言語がさらに複雑になります。しない方がいい。

全体として、コンストラクターを追加することをデフォルトを削除することと考えないことが最善です。何もしないパラメーターなしのコンストラクターを追加するための構文上の砂糖として、コンストラクターをまったく持たないと考える方が良いです。

19
Jon Hanna

オブジェクトの作成を制御するために自分で何もしない場合は、デフォルトのパラメーターなしのコンストラクターが追加されます。単一のコンストラクターを作成して制御を取得すると、コンパイラーは「バックオフ」し、完全に制御できるようになります。

この方法でない場合、オブジェクトをパラメーター付きのコンストラクターのみで構築できるようにする場合は、デフォルトのコンストラクターを無効にする明示的な方法が必要になります。

13
Anders Abel

他のコンストラクターを定義していない場合、デフォルトのコンストラクターを宣言する必要がないのはなぜですか?

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

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

3
Botz3000

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

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

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

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

3
mw_21

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

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

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

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

1
ashes

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

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

1

前提

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

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

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

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

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

パラメーターなしのコンストラクターがない場合、何に置き換える必要がありますか?およびデフォルトのパブリックパラメータレスコンストラクタ?

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

  1. クラスをインスタンス化したくない、またはコンストラクターの可視性を制御したい:declare a non-public constructor
  2. 構築時にパラメーターを強制的に提供したい:declare a constructor with parameters

結論

C#、C++、およびJavaがデフォルトのパブリックパラメータレスコンストラクターの削除を許可するまさに2つの方法があります。

1
Zaid Masud

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

0
Vivek Pradhan

クラスにはコンストラクタが必要です。これは必須の要件です。

  • 作成しない場合は、パラメータなしのコンストラクタが自動的に提供されます。
  • パラメーターなしのコンストラクターが必要ない場合は、独自のコンストラクターを作成する必要があります。
  • パラメーターなしのコンストラクターとパラメーターベースのコンストラクターの両方が必要な場合は、手動で追加できます。

私はあなたに別の質問で答えます、なぜデフォルトのパラメータレスコンストラクタが常に必要なのですか?これが望ましくない場合があるため、開発者は必要に応じて追加または削除するコントロールを持っています。

0
Jaider