C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 팁&트릭
C++Builder Programming Tip&Tricks
[29] 팁! 순환적 클래스참조를 피하기
박지훈.임프 [cbuilder] 10622 읽음    1999-06-04 00:00
임프랍니다.. 오늘도 역시 늦었죠.. 에구~
일찍 오셔서 기다렸을 분께 정말 죄송하구요..
그럼.. 오늘의 팁.. 나갑니다...

빌더는 C++언어에 기반하고 있어서, 오래전 C시절부터 사용해오던 헤더화일 중심의
선언 구조를 그대로 가지고 있습니다. 사실 이 헤더화일이란 구조는 아이덴티파이어의
형을 분명히 해주고 코드와 선언부를 분명히 나누어줘서 좋은 면도 있습니다만
현재에 와서는 빌더가 델파이보다 엄청나게 느린 이유의 하나가 되고 있죠.
빌더에선 이러한 단점을 최소화하기 위해 프리컴파일드 헤더라는 특이한 방법을
사용하고 있죠. 담번에 한번 프리컴파일드 헤더를 최대한 활용하는 방법을
알아보기로 하구요. 오늘은 헤더화일의 다른 면에 대해서 알아봅시다.

한 모듈(편의상 유닛)에서 한 헤더를 두번 인클루드하면?
몇가지 선언에서는 워닝이 뜰거구, 또 몇가지에선 에러가 날 수 있습니다.
C코딩에선 이러한 것을 피하기 위해 오래전부터 다음과 같은 방법을 쓰죠.
만약 헤더화일의 이름이 QQQ.H 라면,

#ifndef QQQH (혹은 QQQ_H)
#define QQQH (    "     )
 
.....(실제 헤더의 내용들)
 
#endif


이렇게 해서 한 헤더화일이 두번 인클루드 되는 것을 막습니다.
왜 이런게 필요하냐구요? 왜냐하면, 실제의 대형화되는 프로젝트에서는
한 헤더에서 다른 헤더를 인클루드하고, 다시 그 헤더에서 다른 헤더를 인클루드
하고.. 이렇게 꼬리에 꼬리를 물고 해서 한 헤더화일이 다시 인클루드되는 경우가
부지기수로 있기 때문이죠. 위와 같은 방법을 쓰면, 만약 이미 QQQ.H가 인클루드
되었다면 QQQH가 미리 선언되어 다음번에 인클루드하려고 할때는 그냥 스킵해
버리게 되는거죠. 빌더의 폼 유닛 헤더는 모두 디폴트로 이러한 검사부분이 포함
되어있습니다. 빌더 뿐 아니라 모든 씨 컴파일러의 표준 헤더에는(예를 들면
stdio.h나 alloc 등의 표준 헤더 말이죠) 이러한 검사 프리프로세서가 포함되어
있습니다.

하지만,  완벽해보이는 이러한 미연의 방지에도 불구하고, 이러한 방법에도
치명적인 단점이 하나 있습니다. 다음과 같은 경우를 가정해봅시다.

MyClass 라는 클래스와, 이 클래스의 멤버가 되는 다른 클래스 MyMeberClass를
생각해봅시다. MyClass는 MyMember클래스만  포함해야 하므로 당연히
MyMemberClass의 헤더를 포함해야 되겠죠? 반대로 MyMemberClass에서도
MyClass를 참조해야 한다면? 그럼 아무 생각없이 인클루드 합니다.

여기서 문제가 생깁니다. MyClass.h와 MyMemberClass.h는 서로 상호 인클루드하고
있습니다. 그렇기 때문에, 만약 먼저 MyClass.h를 컴파일하였다면, 이미
MyMemberClass의 내용까지 모두 컴파일하게 된겁니다. 다시 MyMemberClass.h를
컴파일하려고 할때 (별개의 모듈이므로 다시 컴파일하게 되죠)
MyMemberClass.h는 인클루드 되지 않습니다! 이 헤더의 모든 멤버는 undefined로
에러가 나버릴겁니다. 왜 인클루드 안하냐구요? 바로 위의 #ifndef ~ #endif
구조 때문이죠. 이해가 잘 안되시는 분은 다시한번 찬찬히 읽어보시기 바랍니다.

이러한 경우의 해결책은??
방법은, 다른 클래스를 변수형으로 선언할때는 그 클래스를 추상적으로(단어선택이
적당한지 모르겠는데요) 선언하는 겁니다. 예를 들어서 위의 경우를 구체적으로
보면...

----------------------------- MyClass.h -------------------------------
#include 
 
class MyClass
{
(어쩌구 저쩌구)
 
    MyMemberClass *A_Member;
...
};


-------------------------- MyMemberClass.h ----------------------------
#include 
 
class MyMemberClass
{
...
    MyClass *OwnerObject;
...
};

이렇게 되어선 안된다는 거죠. 이걸 정상적으로 동작하도록 고치면,
----------------------------- MyClass.h -------------------------------
class MyClass
{
(어쩌구 저쩌구)
 
    class MyMemberClass *A_Member;
...
};


-------------------------- MyMemberClass.h ----------------------------
class MyMemberClass
{
...
   class MyClass *OwnerObject;
 
...
};

이렇게 되어야 합니다. (어디에도 다른 한쪽 헤더를 인클루드 한곳이 없다는
것에 주의하세요.) 이 경우에 또 한가지 문제가 되는점이 있는데..
클래스의 형선언이 실제로 되지 않고 그냥 '이건 클래스인줄만 알아라' 라는
식으로 선언했기 때문에, 이 클래스의 멤버를 참조하는 실제 바디 모듈(~.cpp)
에서는 멤버가 undefined로 에러가 납니다.
그래서 바디 모듈에서는 실제 클래스를 인클루드 해줘야 합니다.

말이 좀 헷갈리죠? 이러한 경우를 실제로 당해보지 않으신 분들은 잘 이해가
안될겁니다. 그냥 이런 게 있더라.. 정도만 기억해놓으시고, 빌더라운지에
그 관련 팁이 있었단것만 기억해두면 다음에 실제로 프로젝트를 작성하다가
문제가 생겼을때 참고하시면 되겠습니다. 지금 이해가 안되시는 분은 억지로
이해하려구 하실 필요가 없단 말이죠.

사실 이 주제는.. 어느 C/C++ 책을 봐도 언급된 곳을 못봤고.. 실무의
테크닉이라고 할만한 부분인데다가, 제대로 설명하자면 책을 써도 두세개 섹션은
할당해야 할정도로 좀 이해가 어려운 부분입니다. 정말 필요하신데 이해가 잘
안되시는 분은 다시 질문 올려주시면 답변하도록 하죠.

그럼, 좀 알쏭달쏭하나마, 오늘도 도움되시길 바라면서, 이만...



독립문에서 임펠리테리였습니다.

+ -

관련 글 리스트
29 팁! 순환적 클래스참조를 피하기 박지훈.임프 10622 1999/06/04
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.