C++ ビルド モデルは、Java モデルとはかなり異なります。C++ には、関数、クラス、メソッドなど、さまざまなエンティティの「宣言」と「定義」があります。C++ ソースは、一連の宣言と定義で構成されます。個々のモジュール、または「翻訳単位」は、その翻訳単位で定義されているエンティティを含むオブジェクト コードにコンパイルされます。次に、プログラムを構成するコンパイル済みの翻訳単位が「リンク」され、1 つの翻訳単位で定義されたエンティティが、他の翻訳単位での使用法に接続されます。
翻訳単位では、エンティティの特定の使用法では宣言のみが必要ですが、他の使用法では完全な定義が必要です。たとえば、関数を呼び出すには、関数を宣言するだけで済みます。オブジェクトへのポインターである変数を作成するには、オブジェクトの型を宣言するだけで済みます。型が (ポインターではなく) クラス型である変数を作成するには、クラスの完全な定義が必要です。完全な定義が必要なものと宣言のみが必要なものは、使用法を実装するために何が必要かによって異なります。特に、使用法がインターフェースの詳細のみを知る必要がある場合は宣言で十分ですが、実装の詳細が必要な場合は定義が必要です。
さらに、C++ は、コンパイラがほぼシングル パスになるように指定されています。宣言と定義は、それらが使用される前にソース コードに表示される必要があります (ほとんどの場合、いくつかの例外があります)。これにより、言及されたときにどのエンティティが使用されているかを C++ が認識できるようになります。
したがって、コードの問題は、コンパイラがtest()
それに到達したときに、何が何であるかがわからないことtest
です。型、関数、または変数の可能性があります。それはまだ言われていないのでわかりません。test
事前に宣言して、それを伝える必要があります。
void test();
int main() {
test();
}
これで、コンパイラは、test を呼び出そうとする時点で test が関数であることを認識します。また、関数の呼び出しは、関数のシグネチャ以外は何も知る必要がないため、必要に応じて、 の定義をtest
まったく別の翻訳単位に入れることができます。両方の翻訳単位をコンパイルすると、リンカーは、test()
コンパイルされた他の翻訳単位でその関数の定義を呼び出すコードを接続します。
ヘッダー ファイルは、C および C++ の一般的なトリックであり、翻訳単位間で共有される宣言の単一ソースを簡単に作成できます。これらは厳密に必要というわけではありませんが、異なるファイルでわずかに異なるものを宣言して宣言を台無しにすると、プログラムが予期せぬ予測不可能な方法で失敗する可能性があります。
#include
ディレクティブは、名前を付けたファイルを取り、その内容をソース コードに貼り付けるだけです。このようにして、たとえば関数宣言など、ヘッダーに入れるものはすべて単一のソースになります。そうすれば、あるファイルと別のファイルで何かが少し異なって宣言されているかどうかを心配することなく、必要なすべてのファイルに同一の宣言が含まれていることを確認できます。
クラス定義は、そのクラスが特定の方法で使用されるすべての翻訳単位で繰り返す必要があるため、ヘッダー ファイルに配置することもできます。繰り返しになりますが、すべての翻訳単位で必要な情報を手動で書き出すこともできますが、定義をヘッダーに#include
貼り付けて、ディレクティブにコピーと貼り付けを行わせる方が簡単です。
C++ を学びたい場合は、良い本を入手することをお勧めします。プログラミングにまだ慣れていない場合は、「プログラミング: C++ を使用した原則と実践」をお勧めします。あなたはすでにプログラミングしたと言っているので、Accelerated C++である可能性があるあなたのためのより良い本を聞いたことがあります。