あなたが検討した制限はセマンティクスに関係していないと思います(初期化が同じファイルで定義されている場合、なぜ変更する必要がありますか?)複雑すぎる(新しいコンパイルモデルと既存のモデルを同時にサポートする)か、既存のコードをコンパイルできない(新しいコンパイルモデルを導入し、既存のモデルを削除する)。
C ++コンパイルモデルは、(ヘッダー)ファイルを含めることにより宣言をソースファイルにインポートするCのコンパイルモデルに由来します。このようにして、コンパイラは、含まれているすべてのファイルとそれらのファイルから含まれているすべてのファイルを含む、1つの大きなソースファイルを再帰的に認識します。これにはIMOの1つの大きな利点があります。つまり、コンパイラの実装が容易になるということです。もちろん、インクルードファイルには何でも、つまり宣言と定義の両方を書くことができます。宣言をヘッダーファイルに、定義を.cまたは.cppファイルに配置することをお勧めします。
一方、されている場合、コンパイラは非常によく知っているでコンパイルモデル持つことが可能である宣言インポートされているグローバルシンボルの別のモジュールで定義されているのか、それがされている場合の定義コンパイルグローバルシンボルので提供します現在のモジュール。後者の場合にのみ、コンパイラはこのシンボル(変数など)を現在のオブジェクトファイルに配置する必要があります。
たとえば、GNU Pascala
では、次のa.pas
ようなファイルにユニットを書き込むことができます。
unit a;
interface
var MyStaticVariable: Integer;
implementation
begin
MyStaticVariable := 0
end.
ここで、グローバル変数は同じソースファイルで宣言および初期化されます。
次に、aをインポートしてグローバル変数を使用するさまざまなユニットMyStaticVariable
、たとえばユニットb(b.pas
)を使用できます
。
unit b;
interface
uses a;
procedure PrintB;
implementation
procedure PrintB;
begin
Inc(MyStaticVariable);
WriteLn(MyStaticVariable)
end;
end.
およびユニットc(c.pas
):
unit c;
interface
uses a;
procedure PrintC;
implementation
procedure PrintC;
begin
Inc(MyStaticVariable);
WriteLn(MyStaticVariable)
end;
end.
最後に、メインプログラムでユニットbとcを使用できますm.pas
。
program M;
uses b, c;
begin
PrintB;
PrintC;
PrintB
end.
これらのファイルを個別にコンパイルできます。
$ gpc -c a.pas
$ gpc -c b.pas
$ gpc -c c.pas
$ gpc -c m.pas
そして、次を使用して実行可能ファイルを生成します。
$ gpc -o m m.o a.o b.o c.o
そしてそれを実行します:
$ ./m
1
2
3
ここでのコツは、コンパイラがプログラムモジュールでusesディレクティブを検出すると(たとえば、b.pasでaを使用する)、対応する.pasファイルを含まず、.gpiファイル、つまりプリコンパイルされたファイルを探すことです。インターフェイスファイル(ドキュメントを参照)。これらの.gpi
ファイルは.o
、各モジュールがコンパイルされるときに、コンパイラーによってファイルとともに生成されます。そのため、グローバルシンボルMyStaticVariable
はオブジェクトファイルで一度だけ定義されますa.o
。
Javaは同様の方法で動作します。コンパイラはクラスAをクラスBにインポートするときに、クラスファイルでAを探し、fileを必要としませんA.java
。したがって、クラスAのすべての定義と初期化を1つのソースファイルに入れることができます。
C ++に戻ると、C ++で静的データメンバを別のファイルに定義する必要がある理由は、リンカまたはコンパイラで使用される他のツールによって課せられる制限よりも、C ++コンパイルモデルに関連しています。C ++では、一部のシンボルをインポートすると、現在のコンパイルユニットの一部として宣言を構築することになります。これは、テンプレートがコンパイルされる方法のため、とりわけ重要です。ただし、これは、インクルードファイルにグローバルシンボル(関数、変数、メソッド、静的データメンバー)を定義できない/すべきではないことを意味します。そうしないと、これらのシンボルがコンパイル済みオブジェクトファイルで多重定義される可能性があります。