C++ の前方宣言とは何ですか? 質問する

C++ の前方宣言とは何ですか? 質問する

これリンクには、次のことが書かれていました。

追加.cpp:

int add(int x, int y)
{
    return x + y;
}

メイン:

#include <iostream>
 
int add(int x, int y); // forward declaration using function prototype
 
int main()
{
    using namespace std;
    cout << "The sum of 3 and 4 is " << add(3, 4) << endl;
    return 0;
}

コンパイラがaddコンパイル時に " " が何であるかを認識できるように、前方宣言を使用しましたmain.cpp。前述のように、別のファイルにある使用したいすべての関数に対して前方宣言を記述するのは、すぐに面倒になります。

前方宣言」についてさらに説明していただけますか? 関数内でそれを使用するとどのような問題が生じますかmain?

ベストアンサー1

C++ で前方宣言が必要な理由

コンパイラは、スペルミスがないか、関数に間違った数の引数が渡されていないかを確認する必要があります。そのため、コンパイラは、使用する前にまず 'add' (またはその他の型、クラス、関数) の宣言を確認するように要求します。

これは、コンパイラがコードの検証をより適切に実行し、未解決の問題を整理して、見栄えのよいオブジェクト ファイルを生成できるようにするだけです。前方宣言する必要がなければ、コンパイラは、関数が何であるかに関するすべての可能な推測に関する情報を含むオブジェクト ファイルを生成することになります。また、リンカーは、 add を使用して または を生成するオブジェクト ファイルとリンカーが結合する別のオブジェクト ファイル内に関数が存在するadd可能性があるadd場合、実際に呼び出すことを意図したものを判別するための非常に巧妙なロジックを組み込む必要があります。リンカーが間違った を取得する可能性があります。 を使用したかったのに、うっかりそれを記述し忘れたが、リンカーが既に存在する を見つけてそれが正しいと判断し、代わりにそれを使用したとします。コードはコンパイルされますが、期待どおりには動作しません。adddllexeaddint add(int a, float b)int add(int a, int b)

したがって、物事を明示的に保ち、推測などを避けるために、コンパイラは、使用する前にすべてを宣言することを要求します。

宣言と定義の違い

余談ですが、宣言と定義の違いを知っておくことは重要です。宣言は、何かがどのように見えるかを示すのに十分なコードを提供するだけです。関数の場合、これは戻り値の型、呼び出し規約、メソッド名、引数、およびその型です。ただし、メソッドのコードは必須ではありません。定義の場合、宣言と関数のコードも必要です。

前方宣言によってビルド時間を大幅に短縮する方法

関数の宣言を、すでに関数の宣言が含まれているヘッダーを #include することで、現在のファイル.cppまたはファイルに取り込むことができます。ただし、これによりコンパイルが遅くなる可能性があります。特に、プログラムではなく にヘッダーを組み込む場合は、記述しているすべてのものを #include すると、#include を記述したすべてのヘッダーも #include されるためです。突然、コンパイラは、1 つまたは 2 つの関数のみを使用したい場合でも、コンパイルする必要がある何ページものコードを #include することになります。これを回避するには、前方宣言を使用して、ファイルの先頭に関数の宣言を自分で入力するだけです。少数の関数のみを使用している場合は、常にヘッダーを #include する場合と比較して、コンパイルが非常に速くなります。非常に大規模なプロジェクトの場合、違いは 1 時間以上かかるコンパイル時間を数分に短縮できる可能性があります。.h#include.h.cpp.h

2つの定義が互いに使用する循環参照を解除する

さらに、前方宣言は循環を断ち切るのに役立ちます。これは、2 つの関数がお互いを使用しようとする場合です。これが発生すると (これは完全に有効なことです)、#include1 つのヘッダー ファイルを使用できますが、そのヘッダー ファイルは#include現在作成中のヘッダー ファイルを使用しようとします... 次に、もう 1 つのヘッダーを #include し、そのヘッダーが作成中のヘッダーを #include します。各ヘッダー ファイルが他のヘッダーを再度 #include しようとすると、鶏が先か卵が先かという状況に陥ってしまいます。これを解決するには、必要な部分をいずれかのファイルで前方宣言し、そのファイルでは #include を省略します。

例えば:

ファイル Car.h

#include "Wheel.h"  // Include Wheel's definition so it can be used in Car.
#include <vector>

class Car
{
    std::vector<Wheel> wheels;
};

ファイル Wheel.h

うーん...には へのポインターがあるため、ここではの宣言がCar必要ですが、をここに含めるとコンパイラ エラーが発生するため含めることはできません。 が含まれていると、 が を含めようとし、が を含め、が を含め、これが永遠に続くため、代わりにコンパイラがエラーを発生させます。解決策は、代わりに前方宣言することです。WheelCarCar.hCar.hWheel.hCar.hWheel.hCar

class Car;     // forward declaration

class Wheel
{
    Car* car;
};

クラスWheelに のメソッドを呼び出す必要があるメソッドがある場合Car、それらのメソッドは で定義できWheel.cpp、循環を起こさずにWheel.cppを含めることができるようになりました。Car.h

おすすめ記事