そうですよね?
いいえ。
関数宣言と関数定義の違い、コンパイル、リンク、実行の違い、非仮想関数と仮想関数の違いを理解する必要があります。
関数宣言
これは関数宣言です: void max(void);
. 関数が何をするかについてコンパイラに何も伝えません。関数の呼び出し方法と結果の解釈方法をコンパイラに指示します。コンパイラが関数の本体をコンパイルしているとき、それを関数 A と呼びます。コンパイラは、他の関数が何をするかを知る必要はありません。知る必要があるのは、関数 A が呼び出す関数をどうするかだけです。コンパイラは、C++ 関数呼び出しに対応するアセンブリ言語または中間言語でコードを生成する場合があります。または、コードが意味をなさないために C++ コードを拒否する可能性があります。
コードが意味をなすかどうかを判断することは、これらの関数宣言のもう 1 つの重要な目的です。これは、複数の関数が同じ名前を持つことができる C++ では特に重要です。max
コンパイラーは、それらの関数について知らなかった場合、どの関数を呼び出すべきかをどのように知るのでしょうか? C++ コードが何らかの関数を呼び出す場合、コンパイラはそれらの関数宣言の 1 つと最も一致するもの (おそらく型変換を含む) を 1 つ見つける必要があります。コンパイラが一致をまったく見つけられない場合、または複数の一致が見つかったが最適な一致として区別できない場合、コードは意味がありません。
コンパイラが最適な一致を見つけた場合、生成されたコードは、その関数への未定義の外部参照への呼び出しの形式になります。その関数が存在する場所は、コンパイラの仕事ではありません。
関数定義
それvoid max(void)
は関数宣言でした。対応するvoid max() {...}
のは、その関数の定義です。コンパイラが処理void max() {...}
しているとき、他の関数が何を呼び出したかについて心配する必要はありません。処理について心配するだけvoid max() {...}
です。この関数の本体は、コンパイルされたオブジェクト ファイルに挿入されるアセンブリまたは中間言語コードになります。コンパイラは、この生成されたコードへのエントリ ポイントのアドレスをそのようにマークします。
コンパイルとリンク
ここまで、コンパイラの機能について説明してきました。C++ コードに対応する低レベル コードのチャンクを生成します。その生成されたコードは、それらの外部参照のために、プライムタイムの準備ができていません. これらの未定義の外部参照を解決するのは、リンカーの仕事です。リンカーは、複数のオブジェクト ファイル、複数のライブラリから実行可能ファイルを構築するものです。これらのコードのチャンクを実行可能ファイルのどこに配置したかを追跡します。これらの未定義の外部参照はどうですか? リンカーがその参照を実行可能ファイルに既に配置している場合、リンカーは単にその参照のプレースホルダーを埋めます。リンカーがその参照の定義に遭遇していない場合、参照とプレースホルダーをまだ解決されていない参照のリストに入れます。リンカーがコードのチャンクを実行可能ファイルに追加するたびに、そのリストをチェックして、まだ解決されていない参照を修正できるかどうかを確認します。最後に、すべての参照が解決されるか、いくつかの未解決の参照が残ることになります。後者はエラーです。前者は、実行可能ファイルがあることを意味します。
実行コードが実行されるとき、これらの関数呼び出しは実際には、その邪悪なステートメント
に相当する機械語にラップされたスタック管理にすぎません。goto
関数宣言を調べる必要はありません。それらは、コードが実行されるまでには存在しません。戻る?それgoto
もね。
非仮想機能
と仮想機能 上記で述べたことは、非仮想機能に関するものです。仮想機能に対して実行時のディスパッチが発生します。その実行時のディスパッチは、関数宣言の検査とは何の関係もありません。これらの仮想関数は、おそらく別の質問の問題です。
最後にもう 1 つ:
喫煙
の習慣をusing namespace std;
やめましょう。それは喫煙に似ていると考えてください。それは悪い習慣です。