ヘッダーファイルは、クラス内のすべての関数とデータメンバーの「概要」を提供するため、C ++ソースファイルを参照するときに役立ちます。他の多くの言語(Ruby、Python、Javaなど)にこのような機能がないのはなぜですか?これは、C ++の冗長性が役立つ領域ですか?
ヘッダーファイルは、クラス内のすべての関数とデータメンバーの「概要」を提供するため、C ++ソースファイルを参照するときに役立ちます。他の多くの言語(Ruby、Python、Javaなど)にこのような機能がないのはなぜですか?これは、C ++の冗長性が役立つ領域ですか?
回答:
ヘッダーファイルの本来の目的は、Cでのシングルパスコンパイルとモジュール化を可能にすることでした。使用する前にメソッドを宣言することにより、シングルコンパイルパスのみが許可されました。この時代は、パワフルなコンピューターが問題なくマルチパスコンパイルを行うことができ、時にはC ++コンパイラーよりも高速であったため、長い間過ぎ去っています。
C ++との後方互換性は、ヘッダーファイルを保持するために必要でしたが、ヘッダーファイルの上に多くを追加したため、非常に問題のある設計になりました。FQAの詳細。
モジュール性のために、モジュール内のコードに関するメタデータとしてヘッダーファイルが必要でした。例えば。どのメソッド(およびC ++クラス)がどのライブラリで利用可能か。コンパイル時間が高価だったため、開発者にこれを書いてもらうのは明らかでした。最近では、コンパイラーがコード自体からこのメタデータを生成しても問題ありません。Javaおよび.NET言語は通常これを行います。
だから ヘッダーファイルは適切ではありません。コンパイラとリンカーを別々のフロッピーに配置する必要があり、コンパイルには30分かかりました。今日、彼らは邪魔をするだけで、悪いデザインの兆候です。
ドキュメントの形式としては役に立つかもしれませんが、ヘッダーファイルを取り巻くシステムは非常に非効率的です。
Cは、各コンパイルパスが単一のモジュールを構築するように設計されました。各ソースファイルは、コンパイラの個別の実行でコンパイルされます。一方、ヘッダーファイルは、それらを参照する各ソースファイルのコンパイル手順に挿入されます。
これは、ヘッダーファイルが300個のソースファイルに含まれている場合、プログラムのビルド中に300回別々に解析およびコンパイルされることを意味します。まったく同じ結果で、何度も繰り返します。これは膨大な時間の浪費であり、CおよびC ++プログラムのビルドに非常に長い時間がかかる主な理由の1つです。
すべての現代言語は、この非合理的な非効率性を意図的に回避しています。代わりに、通常コンパイルされた言語では、必要なメタデータがビルド出力内に格納され、コンパイルされたファイルがコンパイルされたファイルに含まれるものを記述する一種のクイックルックアップ参照として機能できるようにします。ヘッダーファイルのすべての利点は、追加作業なしで自動的に作成されます。
インタープリター言語では、ロードされるすべてのモジュールはメモリに残ります。一部のライブラリを参照または含めるか、必要とすると、関連するソースコードが読み取られてコンパイルされ、プログラムが終了するまで常駐します。他にも必要な場合は、既にロードされているため追加の作業はありません。
どちらの場合でも、言語のツールを使用して、このステップで作成されたデータを「ブラウズ」できます。通常、IDEには何らかのクラスブラウザがあります。また、言語にREPLがある場合は、ロードされたオブジェクトのドキュメントサマリーを生成するためにも頻繁に使用できます。
ヘッダーファイルは、クラス変数などのいくつかの追加情報とともに、すべて1つの見やすいファイルで実装へのインターフェイスの形式を提供するため、常に気に入っていました。
クラスごとに2つのファイルを使用して記述された多くのC#コード(クラスごとに2つのファイルを必要としない)が表示されます。1つは実際のクラス実装で、もう1つはインターフェイスです。この設計は、モッキング(一部のシステムでは必須)に適していて、IDEを使用してコンパイル済みメタデータを表示することなく、クラスのドキュメントを定義するのに役立ちます。私はこれまでのところ、その良い習慣を言うつもりです。
したがって、C / C ++がヘッダーファイルで同等の(ある種の)インターフェイスを強制するのは良いことです。
「2つのファイルに物を入れる必要があるとコードをハックするのが難しい」などの理由でそれらを好まない他のシステムの支持者がいることは知っていますが、私の態度はコードをハックするだけでは良い習慣ではないということです、もう少し考えてコードの作成/設計を開始すると、当然のことながらヘッダー/インターフェイスを定義することになります。
実際、ヘッダーファイルは、インターフェイスと実装が濁っているため、あまり良くありません。プログラミング全般、特にOOPの目的は、定義されたインターフェイスを持ち、実装の詳細を隠すことですが、C ++ヘッダーファイルには、メソッド、継承、パブリックメンバー(インターフェイス)、プライベートメソッドおよびプライベートメンバーの両方が表示されます(実装の一部)。言うまでもなく、場合によってはヘッダーファイルにコードまたはコンストラクターをインライン化し、一部のライブラリにはヘッダーにテンプレートコードが含まれます。これにより、実装とインターフェイスが実際に混在します。
元々の意図は、スクリプトの内容全体をインポートすることなく、コードが他のライブラリ、オブジェクトなどを使用できるようにすることだったと思います。必要なのは、コンパイルしてリンクするヘッダーだけです。そのようにして時間とサイクルを節約します。その場合、それはまともなアイデアですが、これらの問題を解決する方法の1つにすぎません。
プログラムの構造の閲覧に関しては、ほとんどのIDEがその機能を提供しており、インターフェイスをキックアウトしたり、コード分析、逆コンパイルなどを行ったりする多くのツールがあります。
他の言語が同じ機能を実装しないのはなぜですか?なぜなら、他の言語は他の人から来ており、それらのデザイナー/クリエーターは物事がどのように機能するべきかについて異なるビジョンを持っているからです。
最良の答えは、あなたがしなければならない仕事を何に固執し、あなたを幸せにすることです。
多くのプログラミング言語では、プログラムが複数のコンパイル単位に細分化されると、コンパイラがそれらの内容を知る手段を持っている場合、あるユニットのコードは別のユニットで定義されたもののみを使用できます。1つのコンパイル単位を処理するコンパイラーが、現在のユニット内で使用されるものを定義するすべてのコンパイル単位のテキスト全体を検査することを要求するのではなく、コンパイラーは、各ユニットの処理中に、コンパイルされるユニットの全文を受け取るのが最善です他のすべてからの少しの情報で。
Cでは、プログラマーは各ユニットに対して2つのファイルを作成する責任があります。1つはそのユニットのコンパイル時にのみ必要な情報を含み、もう1つは他のユニットのコンパイル時に必要な情報を含みます。これはやや厄介でハックの多い設計ですが、コンパイラが中間ファイルを生成および処理する方法について言語標準で指定する必要がなくなります。他の多くの言語は異なるアプローチを使用します。コンパイラは、各ソースファイルから、外部コードからアクセスできるはずのソースファイル内のすべてを記述する中間ファイルを生成します。このアプローチにより、2つのソースファイルに重複した情報を含める必要がなくなりますが、コンパイルプラットフォームでCに不要な方法でファイルのセマンティクスを定義する必要があります。