본문 바로가기
Programming/C++

[C++] 헤더파일(.h) 내용 중복 include 방지 방법

by 롱일스 2020. 8. 27.
반응형

.h 헤더파일 내용이 중복되면 컴파일 에러가 발생한다. 

이걸 방지하기 위해 사용되는 방법들을 알아보겠다.

 

먼저, 만보기 프로그램을 만든다고 생각해보자. 

만보기에는 두 가지 버튼이 있다. 리셋 버튼과 숫자를 세는 버튼, reset & count 버튼으로 구성됐다고 하자.

만보기

이 프로그램을 만들기 위해 만보기의 기본적인 기능을 가지는 클래스인 Counter 클래스를 만들어보자.

 

●  Counter 클래스 명세

만보기를 나타내는 클래스를 선언한다. 만보기 객체는 값을 0으로 지울 수 있고, 값을 1씩 증가시킬 수 있고, 현재 만보기의 값을 알려주는 기능이 있어야 한다.

  ▷ 행위

메소드 비고
void reset() 만보기의 값을 0으로 초기화한다.
void count() 만보기의 값을 +1 증가시킨다.
int getValue() 만보기의 현재 값을 알려준다.

  ▷ 속성

속성 비고
int value 만보기의 현재 값을 저장한다.

  ▷ Counter 클래스

Counter 클래스
-value:int
+reset() : void
+count() : void
+getValue() : int

 

●  소스 파일의 구성

 

●  헤더파일 내용의 중복 경우

  ▷ Case 1

/* Counter.h */
class Counter {
    //클래스 멤버 선언
    ....
};

+

/* MainRtn.cpp */
#include "Counter.h"
int main()
{
	....
}

선행처리 후 파일이 아래와 같이 해석된다.

/* 선행처리 결과 */

class Counter {
    //클래스 멤버 선언
    ....
};
int main()
{
	....
}

이렇게 되면 정상인데 아래와 같은 상황이 발생할 수도 있다.

  ▷ Case 2

/* Counter.h */
class Counter {
    //클래스 멤버 선언
    ....
};

+

/* ClassA.h */
#include "Counter.h"
class ClassA {
    ....
};

+

/* MainRtn.cpp */

#include "Counter.h"
#inculde "ClassA.h"

int main()
{
	....
}

선행처리 후 파일이 아래와 같이 해석된다.

/* 선행처리 결과 */

class Counter {
    //클래스 멤버 선언
    ....
};
#include "ClassA.h"

int main()
{
	....
}

/* 선행처리 결과 */

class Counter {
    //클래스 멤버 선언
    ....
};
#include "Counter.h"
class ClassA{
    ....
};

int main()
{
	....
}

/* 선행처리 결과 */

class Counter {
    //클래스 멤버 선언
    ....
};
class Counter {
    //클래스 멤버 선언
    ....
};
class ClassA{
    ....
};

int main()
{
	....
}

위와 같이 클래스 멤버를 중복해서 선언하게 된다. --> 에러!!!

이런 상황을 방지하기 위한 방법을 알아보자.

 

●  헤더파일 내용의 중복 include 방지 방법 1

#ifndef SOMETHING 은 if not defined SOMETHING,
즉, SOMETHING이 정의되어 있지 않다면! 이란 뜻이다.

정의되어 있지 않으면 참이므로 다음 문장인
#define SOMETHING으로 가서 정의를 하고 클래스 선언문을 선언한다. 

정의되어 있다면 거짓이 되므로 #endif로 가서 SOMETHING을 정의하지 않는다.

자세히 아래 예를 통해 알아보자.

/* Counter.h */

#ifndef COUNTER_H_INCLUDED
#define COUNTER_H_INCLUDED
class Counter {
    //클래스 멤버 선언
    ....
};
#endif 

+

/* ClassA.h */

#ifndef CLASSA_H_INCLUDED
#define CLASSA_H_INCLUDED
#include "Counter.h"
class ClassA {
    ....
};
#endif 

+

/* MainRtn.cpp */
#include "Counter.h"
#include "ClassA.h"

int main()
{
	....
}

선행처리 결과

class Counter {
	//클래스 멤버 선언
    ....
};
//COUNTER_H_INCLUDED 정의

// #include "Counter.h" --> #ifndef 에서 바로 #endif로 가서 중복선언되지 않는다.
class ClassA {
    ....
};
//CLASSA_H_INCLUDED 정의

int main()
{
	....
}

처음 Counter.h로 Counter 클래스를 정의했고, 그 다음으로 ClassA.h를 통해 ClassA 클래스를 정의한다. 

ClassA.h에 #include "Counter.h"가 있지만 이미 위에서 COUNTER_H_INCLUDED 됐기 때문에, Counter.h가 정의됐기 때문에 정의하지 않고 건너 뛰어서 #endif로 간다. 중복 선언을 막을 수 있다. 가장 보편적으로 사용하는 방법이다! 

 

●  헤더파일 내용의 중복 include 방지 방법 2

#pragma once를 적용하면 헤더파일이 한 번만 적용된다. (비교적 최근 컴파일러에서만 사용 가능하니 적용가능한지 확인하고 사용해야 한다.)

/* Counter.h */

#pragma once
class Counter {
    //클래스 멤버 선언
    ....
};
#endif 

+

/* ClassA.h */

#pragma once
#include "Counter.h"
class ClassA {
    ....
};
#endif 

+

/* MainRtn.cpp */
#include "Counter.h"
#include "ClassA.h"

int main()
{
	....
}

선행처리 결과

class Counter {
	//클래스 멤버 선언
    ....
};

class ClassA {
    ....
};

int main()
{
	....
}

 

이런 간단한 선행처리기(#include, #ifndef 등)를 알고 있으면 디버깅 시간을 줄일 수 있다~!

728x90
반응형