2016-09-01 2 views
0

私が最初にC++を学んだとき、コード内の関数 "宣言"の順序が重要でないJavaのような関数が上から下に作成されていることに気がつきました。一般に、コンパイラ/インタプリタは解釈中に関数を作成することをお勧めしますか?

C++の例:

#include <iostream> 
using namespace std; 

int main() { 
    test(); 
    return 0; 
} 

void test() { 

} 

しかし、あなたは関数の順序を入れ替えるときに、プログラムが正常に動作します。

C++を設計したときにそれは意図的でしたか?

+2

の別の説明を見ることができます。 – alain

+0

関数を宣言するだけで関数を宣言することができます。定義する必要はありません。 – SergeyA

+0

@ SergeyA私はそれを知っています。しかしそれは問題ではない。 – Midnightas

答えて

4

CまたはC++では、使用法と比較して関数定義の順序が厳しくありません。

Cでは、関数を使用する前に宣言することができますが、(C89/90では)それを実際には必要としませんでした。宣言されていない関数が呼び出された場合、コンパイラはその関数の型について特定の前提を設定する必要があります(関数の定義がこれらの前提条件に合わない場合は無効です)。

C++は、しかし、少なくともことfree関数義務は、使用前に を宣言しません。関数定義はその関数も宣言しているので、小さなプログラムは、宣言をその定義とは別に書く必要を避けるために、多くの場合、使用に先行する定義で記述されます。

クラスメンバーの場合、C++は制限を緩和します。例えば、これは完全に許容可能である:

class Foo { 
    void bar() { baz(); } 
    void baz() {} 
}; 

Javaは主に単純にすべてのフリー機能を禁止に異なるので、C++メンバ関数とほぼ同じ規則に従うだけのメンバ関数を有します。


  1. はこれがなければ、そのような関数のオーバーロードなど、いくつかのC++の機能をサポートするために、基本的には不可能であろう。
+0

クラス内に 'bar'を定義する可能性は、C++ 11 IIRCでのみ追加されました。 – alain

+2

@alain:C++ 98以降のクラス定義の中で関数を定義することは許されています。 –

+0

ああ、ありがとう。 (どういうわけか、以前よりも頻繁に使用されているように見えますが、理由はわかりません) – alain

1

問題は、制約のシリーズに由来:

  • 値のセマンティクスがそれをコンパイルする必要がありますが、パラメータを知っているし、種類のサイズを返す必要があります「と呼んで」。
  • コンパイル時に同じ翻訳単位をコンパイルするときに、その知識が利用できる必要がありますが、...
  • 定義から来る知識は、コンパイル時に別のステップであるリンク時にのみ使用できます。

によってより、C++の文法変更の意味を複雑にするには、シンボルを変数や型(そう、この知識がなくても、a<b>cであれば、それが何を意味するのかを知ることさえ不可能です:変数3を含む式かの変数の宣言テンプレートインスタンスによって与えられた型)。

関数定義は別のソースファイルに存在する可能性があり、コンパイラは最初のコンパイル時にアクセスする方法がないため、パラメータと戻り値のスタックにどのくらいの幅を置くべきかを知る必要があります。

//test.cpp 
#include "test.h" //required to check decl & def consistence 
double test() 
{ /*...*/ } 

//main.cpp 
#include "test.h" // required to know about test() parameters and return 
int main() 
{ 
    double z = test(); //how does "=" translate? we need to know what test returns 
} 

この "プロジェクト" __独立した手順を使用してコンパイルされるコードとして

//test.h 
double test(); 

__

幅広いプロジェクト - -inあなたのサンプルは次のようになります。

g++ -c main.cpp //on a program developer machine 
g++ -c test.cpp //on a library developer machine 
g++ main.o test.o -o yourprogram //on a "package distributor" machine 

これらのステップのいずれも、同時にすべての「グローバルシンボル」とその「翻訳」について「グローバルな知識」を集めることはできません。私たちは、すべて同じクラスの括弧の中にとどまることを要求され、メンバ関数は、この問題を持っていないか注意してください、そして結果としてある(それらを

を使用する必要が誰に宣言をブロードキャストするヘッダを必要とする理由です

モジュールは(どのように書き込まれ、ロードされているかに関係なく)すべて同じ言語マシンインスタンスによってロードされるため、JavaやPythonなどの言語にはこの問題はありません。実際にすべてのシンボルと関連するタイプを収集することができます。

Dのような言語(「別々のコンパイル」の意味ではC++に似ています)は、同じモジュールに存在するものの間の順序の独立性を可能にしますが、最初にシンボルとタイプを収集して通話の変換を行い、2段階の翻訳を行います。

あなたははい、私は意図は、コンパイルをスピードアップするためだったと思う。この問題here

関連する問題