당신이 고려한 한계는 의미론과 관련이 없으며 (초기화가 동일한 파일에 정의 된 경우 왜 변경해야합니까?) 오히려 이전 버전과의 호환성 때문에 쉽게 변경할 수없는 C ++ 컴파일 모델과 관련이 있다고 생각합니다. 너무 복잡해 지거나 (새 컴파일 모델과 기존 모델을 동시에 지원함) 기존 코드를 컴파일 할 수 없습니다 (새 컴파일 모델을 도입하고 기존 모델을 삭제하여).
C ++ 컴파일 모델은 (헤더) 파일을 포함하여 선언을 소스 파일로 가져 오는 C의 컴파일 모델에서 비롯됩니다. 이런 식으로 컴파일러는 포함 된 모든 파일과 해당 파일에서 포함 된 모든 파일을 재귀 적으로 포함하는 하나의 큰 소스 파일을 정확하게 볼 수 있습니다. 이것은 IMO에게 하나의 큰 장점, 즉 컴파일러를 쉽게 구현할 수 있다는 것입니다. 물론 포함 된 파일에 선언과 정의 모두를 쓸 수 있습니다. 헤더 파일에는 선언을, .c 또는 .cpp 파일에는 정의를 넣는 것이 좋습니다.
다른 한편으로, 다른 모듈에 정의 된 전역 심볼 의 선언 을 가져 오는지 또는 다음에서 제공 하는 전역 심볼 의 정의 를 컴파일하는 경우 컴파일러가 잘 알고있는 컴파일 모델을 가질 수 있습니다. 현재 모듈 . 후자의 경우에만 컴파일러가이 기호 (예 : 변수)를 현재 객체 파일에 넣어야합니다.
예를 들어 GNU Pascal에서는 다음 과 같이 a
파일에 단위 를 작성할 수 있습니다 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를 찾고 파일이 필요하지 않습니다 A.java
. 따라서 클래스 A에 대한 모든 정의 및 초기화를 하나의 소스 파일에 넣을 수 있습니다.
C ++로 돌아가서 C ++에서 정적 데이터 멤버를 별도의 파일로 정의해야하는 이유는 링커 또는 컴파일러가 사용하는 다른 도구에 의해 부과 된 제한보다 C ++ 컴파일 모델과 더 관련이 있습니다. C ++에서 일부 기호를 가져 오면 현재 컴파일 단위의 일부로 선언을 작성하는 것을 의미합니다. 이는 템플릿이 컴파일되는 방식 때문에 무엇보다 중요합니다. 그러나 이것은 포함 된 파일에서 전역 기호 (함수, 변수, 메소드, 정적 데이터 멤버)를 정의 할 수 없거나 정의해서는 안된다는 것을 의미합니다. 그렇지 않으면 이러한 기호가 컴파일 된 객체 파일에서 다중 정의 될 수 있습니다.