C ++에 별도의 헤더 파일이 필요한 이유는 무엇입니까? 클래스를 작성하고 리팩토링하는 것이 매우

왜 C ++이 .cpp 파일과 동일한 기능을 가진 별도의 헤더 파일을 필요로하는지 이해하지 못했습니다. 클래스를 작성하고 리팩토링하는 것이 매우 어렵고 불필요한 파일을 프로젝트에 추가합니다. 그리고 헤더 파일을 포함해야하지만 이미 포함되어 있는지 명시 적으로 확인해야하는 문제가 있습니다.

C ++은 1998 년에 비준되었으므로 왜 이렇게 설계 되었습니까? 별도의 헤더 파일을 사용하면 어떤 이점이 있습니까?


후속 질문 :

내가 포함하는 모든 것이 .h 파일 일 때 컴파일러는 코드가 포함 된 .cpp 파일을 어떻게 찾습니까? .cpp 파일의 이름이 .h 파일과 같다고 가정합니까, 아니면 실제로 디렉토리 트리의 모든 파일을 살펴 보나요?



답변

헤더 파일에 다른 용도가 있지만 정의와 선언을 분리하는 것에 대해 묻는 것 같습니다.

대답은 C ++이 이것을 “필요하지”않다는 것입니다. 클래스 정의에 정의 된 멤버 함수에 대해 자동으로 모든 것을 인라인으로 표시하면 분리 할 필요가 없습니다. 헤더 파일의 모든 것을 정의 할 수 있습니다.

분리 하려는 이유 는 다음과 같습니다.

  1. 빌드 시간을 향상시킵니다.
  2. 정의의 소스없이 코드에 연결합니다.
  3. 모든 것을 “인라인”으로 표시하지 않기 위해.

더 일반적인 질문이 “왜 C ++과 Java가 동일하지 않습니까?”라면 “왜 Java 대신 C ++를 작성합니까?”라고 물어야합니다. ;-피

더 심각한 이유는 C ++ 컴파일러가 다른 번역 단위에 접근 할 수없고 javac가 할 수 있고하는 방식으로 기호를 사용하는 방법을 알아낼 수 없기 때문입니다. 헤더 파일은 링크 타임에 사용 가능한 것으로 컴파일러에 선언하는 데 필요합니다.

그래서 #include직선 텍스트 대체입니다. 헤더 파일에 모든 것을 정의하면 전처리 기는 프로젝트의 모든 소스 파일을 대량으로 복사하여 붙여 넣고 컴파일러에 공급합니다. C ++ 표준이 1998 년에 비준되었다는 사실은 이와 관련이 없으며, C ++의 컴파일 환경은 C의 컴파일 환경과 매우 밀접한 관련이 있다는 사실입니다.

후속 질문에 답변하기 위해 내 의견을 변환 :

컴파일러는 코드가 포함 된 .cpp 파일을 어떻게 찾습니까?

적어도 헤더 파일을 사용한 코드를 컴파일 할 때가 아닙니다. 링크하는 함수는 아직 작성되어있을 필요는 없으며 컴파일러가 어떤 .cpp파일에 있는지 알지 않아도 됩니다. 컴파일 타임에 호출 코드가 알아야 할 모든 것은 함수 선언에 표시됩니다. 링크 타임에 .o파일 목록 또는 정적 또는 동적 라이브러리 를 제공 할 것이며 사실상 헤더는 함수 정의가 어딘가에있을 것이라는 약속입니다.


답변

C ++은 C가 그렇게했기 때문에 그렇게하는데, 실제 질문은 C가 왜 그렇게했을까요? Wikipedia 는 이것에 대해 조금 말합니다.

최신 컴파일 언어 (예 : Java, C #)는 앞으로 선언을 사용하지 않습니다. 식별자는 소스 파일에서 자동으로 인식되고 동적 라이브러리 심볼에서 직접 읽습니다. 이것은 헤더 파일이 필요하지 않음을 의미합니다.


답변

어떤 사람들은 헤더 파일이 장점이라고 생각합니다 :

  • 인터페이스와 구현의 분리를 활성화 / 강화 / 허용한다고 주장하지만 일반적으로 그렇지 않습니다. 헤더 파일은 구현 세부 사항으로 가득합니다 (예 : 클래스의 멤버 변수는 공용 인터페이스의 일부가 아니더라도 헤더에 지정해야 함). 함수는 클래스 선언 에서 인라인 으로 정의 될 수 있으며 종종 정의됩니다 헤더에서 다시이 분리를 파괴합니다.
  • 각 변환 단위를 독립적으로 처리 할 수 ​​있기 때문에 컴파일 타임을 향상시키는 경우가 있습니다. 그러나 C ++은 컴파일 타임과 관련하여 가장 느린 언어 일 것입니다. 이유의 일부는 동일한 헤더를 여러 번 반복해서 포함하기 때문입니다. 여러 번역 단위에 많은 수의 헤더가 포함되어 있으므로 여러 번 구문 분석해야합니다.

궁극적으로 헤더 시스템은 C가 디자인되었을 때 70 년대의 인공물입니다. 당시 컴퓨터에는 메모리가 거의 없었으며 전체 모듈을 메모리에 보관하는 것은 선택 사항이 아닙니다. 컴파일러는 맨 위에서 파일 읽기를 시작한 다음 소스 코드를 통해 선형으로 진행해야했습니다. 헤더 메커니즘이이를 가능하게합니다. 컴파일러는 다른 변환 단위를 고려할 필요가 없으며 코드를 위에서 아래로 읽어야합니다.

그리고 C ++은 이전 버전과의 호환성을 위해이 시스템을 유지했습니다.

오늘날은 말이되지 않습니다. 비효율적이며 오류가 발생하기 쉽고 복잡합니다. 그것이 목표 라면 인터페이스와 구현을 분리하는 훨씬 더 좋은 방법이 있습니다 .

그러나 C ++ 0x에 대한 제안 중 하나는 적절한 모듈 시스템을 추가하여 .NET 또는 Java와 유사한 코드를 더 큰 모듈로 컴파일 할 수 있도록하는 것입니다. 이 제안은 C ++ 0x에서 삭감되지는 않았지만 여전히 “나중에이 작업을 수행하고 싶습니다”범주에 속한다고 생각합니다. 아마도 TR2 또는 이와 유사한 것입니다.


답변

내 (제한적-나는 일반적으로 C 개발자가 아닙니다) 이해에, 이것은 C에 뿌리를두고 있습니다. C는 클래스 또는 네임 스페이스가 무엇인지 알지 못한다는 것을 하나의 긴 프로그램 일뿐입니다. 또한 함수를 사용하기 전에 선언해야합니다.

예를 들어, 다음은 컴파일러 오류를 제공해야합니다.

void SomeFunction() {
    SomeOtherFunction();
}

void SomeOtherFunction() {
    printf("What?");
}

선언하기 전에 호출하기 때문에 “SomeOtherFunction이 선언되지 않았습니다”라는 오류가 발생합니다. 이 문제를 해결하는 한 가지 방법은 SomeOtherFunction을 SomeFunction 위로 이동하는 것입니다. 또 다른 방법은 함수 서명을 먼저 선언하는 것입니다.

void SomeOtherFunction();

void SomeFunction() {
    SomeOtherFunction();
}

void SomeOtherFunction() {
    printf("What?");
}

이를 통해 컴파일러는 다음과 같은 사실을 알 수 있습니다. 코드 어딘가에 보이면 SomeOtherFunction이라는 함수가 있습니다. 따라서 SomeOtherFunction을 호출하는 코드를 권장하는 경우 당황하지 말고 대신 찾으십시오.

이제 두 개의 다른 .c 파일에 SomeFunction과 SomeOtherFunction이 있다고 가정하십시오. 그런 다음 Some.c에서 # SomeOther.c를 #include해야합니다. 이제 SomeOther.c에 “비공개”기능을 추가하십시오. C는 개인 함수를 알지 못하므로 Some.c에서도 해당 함수를 사용할 수 있습니다.

이것은 .h 파일이 들어오는 곳입니다. 다른 .c 파일에서 액세스 할 수있는 .c 파일에서 ‘내보내기’하려는 모든 함수 (및 변수)를 지정합니다. 이렇게하면 공개 / 개인 범위와 같은 것을 얻게됩니다. 또한 소스 코드를 공유 할 필요없이이 .h 파일을 다른 사람에게 제공 할 수 있습니다. .h 파일은 컴파일 된 .lib 파일에 대해서도 작동합니다.

따라서 주된 이유는 실제로 편의성, 소스 코드 보호 및 응용 프로그램 부분간에 약간의 분리가 있기 때문입니다.

그래도 C였습니다. C ++에는 클래스와 개인 / 공개 수정자가 도입되었으므로 여전히 필요한지 물어볼 수는 있지만 C ++ AFAIK는 여전히 사용하기 전에 함수 선언이 필요합니다. 또한 많은 C ++ 개발자는 C 개발자이거나 C 개발자이며 개념과 습관을 C ++로 인수했습니다. 왜 부서지지 않은 것을 변경합니까?


답변

첫 번째 장점 : 헤더 파일이 없으면 다른 소스 파일에 소스 파일을 포함시켜야합니다. 이로 인해 포함 된 파일이 변경 될 때 포함 파일이 다시 컴파일됩니다.

두 번째 장점 : 서로 다른 유닛 (다른 개발자, 팀, 회사 등)간에 코드를 공유하지 않고도 인터페이스를 공유 할 수 있습니다.


답변

헤더 파일의 필요성은 컴파일러가 다른 모듈의 함수 및 / 또는 변수에 대한 유형 정보를 알고 있어야하는 한계로 인해 발생합니다. 컴파일 된 프로그램 또는 라이브러리에는 다른 컴파일 단위로 정의 된 객체에 바인딩하기 위해 컴파일러에서 필요한 유형 정보가 포함되어 있지 않습니다.

이 제한을 보완하기 위해 C 및 C ++에서 선언을 허용하며 이러한 선언을 전 처리기의 #include 지시문을 사용하여이를 사용하는 모듈에 포함시킬 수 있습니다.

반면에 Java 또는 C #과 같은 언어에는 컴파일러 출력 (클래스 파일 또는 어셈블리)에 바인딩하는 데 필요한 정보가 포함됩니다. 따라서 더 이상 모듈의 클라이언트가 독립형 선언을 포함 할 필요가 없습니다.

바인딩 정보가 컴파일러 출력에 포함되지 않는 이유는 간단합니다. 런타임에 필요하지 않습니다 (컴파일시 유형 검사가 수행됨). 공간을 낭비 할뿐입니다. C / C ++는 실행 파일이나 라이브러리의 크기가 상당히 중요한 시점에서 나온다는 것을 기억하십시오.


답변

C ++는 언어 자체에 관한 것이 아닌 C에 대한 어떠한 것도 불필요하게 변경하지 않고 C 프로그래밍에 현대적인 프로그래밍 언어 기능을 추가하도록 설계되었습니다.

그렇습니다.이 시점에서 (첫 번째 C ++ 표준 10 년 후, 사용량이 심각하게 증가한 20 년 후) 적절한 모듈 시스템이없는 이유를 쉽게 알 수 있습니다. 분명히 오늘날 새로운 언어는 C ++처럼 작동하지 않을 것입니다. 그러나 이것이 C ++의 요점이 아닙니다.

C ++의 요점은 진화하고 기존 관행을 원활하게 유지하며 사용자 커뮤니티에 적절하게 작동하는 것들을 너무 자주 파괴하지 않고 새로운 기능을 추가하는 것입니다.

이것은 다른 언어보다 더 어렵게 (특히 새로운 프로젝트를 시작하는 사람들에게) 더 쉬운 것을 만들고 (특히 기존 코드를 유지하는 사람들에게) 더 쉽다는 것을 의미합니다.

따라서 C ++이 C # (이미 C #이있는 것처럼 의미가 없음)으로 바뀔 것으로 기대하는 대신, 작업에 적합한 도구를 선택하는 것이 어떻습니까? 나 자신은 현대 언어로 새로운 기능을 많이 작성하려고 노력하고 있으며 (C #을 사용하게 됨) C ++로 유지하는 기존 C ++이 많이 있습니다. 다시 쓸 가치가 없기 때문입니다. 모두. 그들은 어쨌든 아주 잘 통합되어 있기 때문에 크게 고통스럽지 않습니다.