.h 파일에서 #ifndef CLASS_H 및 #define CLASS_H를 사용하지만 왜 .cpp에서는 사용하지 않습니까? 포함 된 .cpp

나는 사람들이 쓰는 것을 항상 보았다

class.h

#ifndef CLASS_H
#define CLASS_H

//blah blah blah

#endif

문제는 클래스 함수에 대한 정의가 포함 된 .cpp 파일에 대해서도 그렇게하지 않는 이유는 무엇입니까?

내가 main.cpp있고 main.cpp포함 한다고 가정 해 봅시다 class.h. class.h파일은하지 않는 include것을, 그래서 어떻게 main.cpp에 뭔지 알아 class.cpp?



답변

먼저, 첫 번째 질문을 해결하십시오.

.h 파일 에서 이것을 볼 때 :

#ifndef FILE_H
#define FILE_H

/* ... Declarations etc here ... */

#endif

이것은 헤더 파일이 여러 번 포함되는 것을 방지하는 전 처리기 기술로, 여러 가지 이유로 문제가 될 수 있습니다. 프로젝트를 컴파일하는 동안 각 .cpp 파일 (일반적으로)이 컴파일됩니다. 간단히 말하면 컴파일러가 .cpp 파일 을 가져 와서 파일을 열고 #included하나의 거대한 텍스트 파일로 연결 한 다음 구문 분석을 수행하고 마지막으로 중간 코드로 변환하고 다른 코드를 최적화 / 수행합니다 마지막으로 대상 아키텍처에 대한 어셈블리 출력을 생성합니다. 이 때문에 파일이 #included하나의 .cpp 아래에 여러 번 있는 경우파일에서 컴파일러는 파일 내용을 두 번 추가하므로 해당 파일 내에 정의가 있으면 변수를 다시 정의했다는 컴파일러 오류가 발생합니다. 파일이 컴파일 프로세스의 전 처리기 단계에 의해 처리 될 때, 내용이 처음 도달 할 때 처음 두 줄은 FILE_H전처리기에 대해 정의되어 있는지 확인합니다 . 그렇지 않으면 FILE_H코드와 #endif지시문 사이의 코드를 정의 하고 계속 처리합니다 . 다음 번에 프리 프로세서가 파일 내용을 볼 때, 검사 FILE_H는 거짓이므로 즉시 스캔 #endif한 후 계속 진행합니다. 이는 재정의 오류를 방지합니다.

그리고 두 번째 관심사를 해결하기 위해 :

일반적으로 C ++ 프로그래밍에서는 개발을 두 가지 파일 형식으로 분리합니다. 하나는 확장자가 .h 이며이를 “헤더 파일”이라고합니다. 일반적으로 함수, 클래스, 구조체, 전역 변수, typedef, 전처리 매크로 및 정의 등의 선언을 제공합니다. 기본적으로 코드에 대한 정보 만 제공합니다. 그런 다음 “코드 파일”이라고하는 확장명이 .cpp 입니다. 이것은 함수, 클래스 멤버, 정의가 필요한 모든 구조체 멤버, 전역 변수 등에 대한 정의를 제공합니다. 따라서 .h 파일은 코드 를 선언 하고 .cpp 파일은 해당 선언을 구현합니다. 이러한 이유로 컴파일 할 때 일반적으로 각 .cpp를 컴파일합니다.하나의 .cpp 파일이 다른 .cpp 파일을 포함하는 것을 거의 볼 수 없기 때문에 파일을 객체에 연결 한 다음 해당 객체를 연결하십시오 .

이러한 외부 장치를 해결하는 방법은 링커의 작업입니다. 컴파일러가 main.cpp를 처리 할 때 class.h 를 포함 시켜 class.cpp 의 코드에 대한 선언을 가져 옵니다 . 이러한 함수 나 변수가 어떤 모양인지 (알선이 제공하는 것) 만 알면됩니다. 따라서 main.cpp 파일을 일부 객체 파일로 컴파일합니다 ( main.obj 라고 ). 마찬가지로 class.cpp은 (A) 내로 컴파일 class.obj파일. 최종 실행 파일을 생성하기 위해 링커가 호출되어이 두 개체 파일을 함께 연결합니다. 해결되지 않은 외부 변수 또는 함수의 경우 컴파일러는 액세스가 발생하는 위치에 스텁을 배치합니다. 링커는이 스텁을 가져 와서 나열된 다른 오브젝트 파일에서 코드 또는 변수를 찾은 후 발견되면 두 오브젝트 파일의 코드를 출력 파일로 결합하고 스텁을 함수의 최종 위치 또는 변하기 쉬운. 이런 식으로 main.cpp의 코드는 함수를 호출하고 class.cpp의 변수를 사용할 수 있습니다. 선언 된 경우 에만 class.h .

도움이 되었기를 바랍니다.


답변

CLASS_H경비를 포함한다 ; 동일한 CPP 파일 (또는보다 정확하게는 동일한 번역 단위 ) 내에 동일한 헤더 파일이 여러 번 (다른 경로를 통해) 포함되지 않도록하는 데 사용됩니다. ) 다중 정의 오류를 초래합니다.

정의에 따라 CPP 파일의 내용은 한 번만 읽기 때문에 CPP 파일에는 포함 가드가 필요하지 않습니다.

포함 가드 import가 다른 언어 (예 : Java)의 명령문 과 동일한 기능을 갖는 것으로 해석 한 것 같습니다 . 그러나 그렇지 않습니다. 그 #include자체는 import다른 언어 와 거의 같습니다 .


답변

적어도 컴파일 단계에서는 그렇지 않습니다.

소스 코드에서 기계 코드로의 C ++ 프로그램 변환은 세 단계로 수행됩니다.

  1. 전처리 -전처리 기는 #으로 시작하는 행에 대한 모든 소스 코드를 구문 분석하고 지시문을 실행합니다. 귀하의 경우 파일의 내용 class.h이 줄 대신에 삽입됩니다 #include "class.h. 헤더 파일에 여러 위치에 포함될 수 #ifndef있으므로, 전 처리기 지시문이 헤더 파일을 처음 포함 할 때만 정의되지 않기 때문에이 절은 중복 선언 오류를 피합니다.
  2. 컴파일 -컴파일러는 이제 사전 처리 된 모든 소스 코드 파일을 이진 객체 파일로 변환합니다.
  3. 연결 -링커는 객체 파일을 연결합니다 (따라서 이름). 클래스 또는 그 메소드 중 하나에 대한 참조 (class.h에 선언되고 class.cpp에 정의되어야 함)는 오브젝트 파일 중 하나의 해당 오프셋으로 해석됩니다. 수업이 필요 하지 않으므로 ‘개체 파일 중 하나’를 작성 합니다. class.cpp라는 파일에 정의 프로젝트에 연결된 라이브러리에있을 수 있으므로 를 작성합니다.

요약하면 선언은 헤더 파일을 통해 공유 할 수 있지만 선언을 정의에 매핑하는 것은 링커에서 수행합니다.


답변

이것이 선언과 정의의 구별입니다. 헤더 파일에는 일반적으로 선언 만 포함되며 소스 파일에는 정의가 포함됩니다.

무언가를 사용하려면 그것이 정의가 아니라 선언임을 알아야합니다. 링커 만 정의를 알아야합니다.

따라서 하나 이상의 소스 파일에 헤더 파일을 포함하지만 다른 파일에는 소스 파일을 포함하지 않습니다.

또한 당신은 의미 #include하고 수입하지 않습니다.


답변

헤더 파일에 대해 수행되므로 내용이 두 번 이상 포함 된 경우에도 (보통 다른 헤더 파일에 포함되어 있기 때문에) 각 사전 처리 된 소스 파일에 한 번만 표시됩니다. 처음 포함 된 경우 기호 CLASS_H( include guard 라고 함 )가 아직 정의되지 않았으므로 파일의 모든 내용이 포함됩니다. 이렇게하면 심볼이 정의되므로 다시 포함되면 파일의 내용 ( #ifndef/#endif 블록 )을 건너 뜁니다.

소스 파일 자체에는 다른 파일에 포함되지 않기 때문에이 작업을 수행 할 필요가 없습니다.

마지막 질문 class.h에는 클래스의 정의와 모든 멤버의 선언, 관련 함수 및 그 밖의 모든 것을 포함하여 클래스를 포함하는 파일이 클래스를 사용하기에 충분한 정보를 갖도록해야합니다. 함수의 구현은 별도의 소스 파일로 갈 수 있습니다. 당신은 그것들을 호출 할 선언 만 필요합니다.


답변

main.cppclass.cpp에 무엇이 있는지 알 필요가 없습니다 . 사용할 함수 / 클래스의 선언 만 알면 되고 이러한 선언은 class.h에 있습니다.

링커는 class.h 에 선언 된 함수 / 클래스 가 사용되는 장소와 class.cpp 의 구현 사이를 연결합니다.


답변

.cpp파일은 #include다른 파일에 포함되어 있지 않습니다 . 따라서 경비를 포함 할 필요가 없습니다. 모든 것을 지정했기 때문에 Main.cpp구현 한 클래스의 이름과 서명을 알 수 있습니다 . 이것은 헤더 파일의 목적입니다. (에 구현 한 코드 를 정확하게 설명하는 것은 사용자의 몫 입니다 .) 링커의 노력 덕분에 실행 코드가 실행 코드에 제공됩니다 .class.cppclass.hclass.hclass.cppclass.cppmain.cpp