전방 선언에 대해서

전방 선언에 대해서 알아보았습니다. 웹에 게시 된 글들을 여러개 살펴 보았는데 아래의 이유에 의해서 사용된다는 결론을 내리게 되었습니다.


불필요한 헤더 파일이 복잡하게 포함되는 것을 방지하며, Compile 속도를 향상 시켜줍니다.


그럼, 위의 결론을 아래와 같은 클래스 구조를 가정하여 설명하도록 하겠습니다.

위 클래스 구조를 보면 CUser클래스가 CManager 클래스를 사용하고 있고 CManager 클래스는 CModuleOne과 CModuleTwo 클래스를 사용하고 있습니다. 이 경우 CUser클래스는 CManager클래스를 사용하는 동시에 이 클래스를 통해서 CModuleOne과 CModuleTwo의 기능을 사용할 것입니다. 결국 CUser 클래스는 CManager 클래스만 알면 되는 것이지요. 만약, CManager 클래스가 CModuleOne과 CModuleTwo 클래스를 멤버변수로 관리하고 있다고 가정할때 전방선언을 하지 않고 헤더파일을 직접 포함하고 있다면 어떻게 될까요? CUser는 굳이 포함할 필요가 없는 CModuleOne 클래스와 CModuleTwo 클래스의 헤더파일들을 포함하게 되어버립니다. 즉, 아래 코드와 같이 되어버리는 것이지요.

아래는 CManager클래스의 헤더파일 내용입니다.


#pragma once

#include "ModuleOne.h"
#include "ModuleTwo.h"

class CManager
{
public:
 CManager(void);
 ~CManager(void);
};

아래는 CManager클래스의 헤더파일을 포함하고 있는 CUser클래스의 cpp 내용입니다.

#include ".\user.h"
#include "Manager.h"

CUser::CUser(void)
{
}

CUser::~CUser(void)
{
}


이는 곧 컴파일 속도를 저해하는 원인이 됩니다. 이유에 대해서 예를 들면, CModuleTwo 클래스를 수정했을 경우 이를 직접적으로 사용하고 있는 CManager 클래스만 함께 컴파일 되면 되는데 이를 직접적으로 사용하고 있지 않음에도 불구하고 CManager클래스의 헤더에 CModuleTwo클래스의 헤더가 포함되어 있기 때문에 CUser 클래스까지 함께 컴파일이 되어버리기 때문입니다.

아래는 위 코드를 컴파일 한 후, CModuleTwo 클래스를 수정하여 다시 컴파일 한 결과 입니다. ModuleTwo.cpp와 Manager.cpp와 함께 User.cpp도 컴파일 되는 것을 확인 하실수 있습니다.


------ Build started: Project: ForwardDeclaration, Configuration: Debug Win32 ------

Compiling...
User.cpp
Generating Code...
Skipping... (no relevant changes detected)
ModuleTwo.cpp
Manager.cpp

Linking...


그럼 위의 문제의 코드를 전방선언으로 고쳐주면 어떻게 될까요? 아래의 코드를 보면 전방선언을 통해 CModuleOne클래스와 CModuleTwo클래스의 헤더를 CManager 클래스의 cpp파일에 숨겼기 때문에 CUser클래스에서는 불필요하게 CModuleOne클래스와 CModuleTwo클래스의 헤더파일이 포함 되는 것을 방지하고 있는 것을 알 수 있습니다.


아래는 CManager클래스의 헤더파일 내용입니다.

#pragma once

class CModuleOne;
class CModuleTwo;


class CManager
{
public:
 CManager(void);
 ~CManager(void);
};

아래는 CManager클래스의 헤더파일을 포함하고 있는 CUser클래스의 cpp 내용입니다.

#include ".\user.h"
#include "Manager.h"


CUser::CUser(void)
{
}

CUser::~CUser(void)
{
}


이는 컴파일 속도의 향상으로 이어집니다. 전방선언을 하지 않고 헤더파일을 직접 포함하고 CModuleTwo 클래스를 수정한 후 컴파일 할 때와 동일하게 전방선언을 하고 CModuleTwo 클래스를 수정한 후 컴파일을 해 보았습니다. 결과는 아래와 같습니다. 헤더파일을 직접 포함한 경우는 User.cpp도 함께 컴파일 되었었지만 이번에는 컴파일에서 제외 되었습니다.


------ Build started: Project: ForwardDeclaration, Configuration: Debug Win32 ------

Compiling...
ModuleTwo.cpp
Generating Code...
Skipping... (no relevant changes detected)
Manager.cpp
Linking...


위 예제는 간단한 클래스로만 이루어졌기 때문에 헤더파일이 복잡하게 얽히는 문제와 컴파일 속도의 향상에 대한 논점이 크게 부각이 되지 않겠지만 이를 실제 프로젝트에 연결지어 생각해 보면 전방선언의 효율성에 대해서 알 수 있습니다.

* 참고 사이트

    김재호의 디지털보단 아날로그 - 전방선언과 컴파일 의존성


다른예시

---------AAA.h-------------------------
#include "BBB.h"

class AAA
{
BBB *bbbInst;
};
----------------------------------------

---------BBB.h-------------------------
#include "AAA.h"

class BBB
{
AAA *aaaInst;
};
----------------------------------------

위와같이 하면 서로의 헤더파일을 무한참조하기 때문에 #pragma once 나 #ifndef 랩핑 방법으로도 해결할 수가 없습니다. 



이럴때는 전방선언을 해주면 문제가 해결됩니다. 

---------AAA.h-------------------------
class BBB;

class AAA
{
BBB *bbbInst;
};
----------------------------------------

---------BBB.h-------------------------
class AAA;

class BBB
{
AAA *aaaInst;
};
----------------------------------------

주의할점은 전방선언을 한 클래스는 실제 클래스가 없는 빈 껍데기이기 때문에 레퍼런스 변수나 포인터 변수 선언시에만 유효합니다. 


만약 이렇게 하면 에러가 나겠죠

---------AAA.h-------------------------
class BBB;

class AAA
{
BBB bbbInst;
};
----------------------------------------



헤더끼리의 의존성을 줄여야 하기 때문에 서로의 헤더를 참조해야 하는 클래스의 경우 저렇게 헤더 파일에서는 전방선언을 한 뒤에 실제 사용되는 CPP 파일에서 인클루드 해주시면 문제가 생기지도 않고 C++ 에서도 권장되는 방법입니다. 


Posted by 모과이IT
,