핵심은 C++가 인터페이스와 구현을 깔끔하게 분리하는 일.
어떻게 정의 됐는지 모르면 컴파일 자체가 불가능.
정의 된 정보를 가져 오려면 #include를 써서 가져와야 함.
#include "Date.h"
#include "Address.h"
이렇게 #include를 사용하면, 컴파일 의존성이 생겨 버린다.
즉, Date와 Address를 변경하면, 변경하지 않은, CPerson도 컴파일 하게 됨.
- 객체 참조자 및 포인터로 충분한 경우에는 객체를 직접 쓰지 않는다.
- 할 수 있으면 클래스 정의 대신 클래스 선언에 최대한 의존.
- 선언부와 정의부에 대해 별로의 헤더 파일을 제공.
pimpl 관용구("pointer to implementation")
PersonImpl.h
Person.h
Person.cpp
멤버 함수를 호출하면 구현부 객체의 데이터까지 가기 위해 포인터를 타야 함.
#ifndef _PERSONIMPL_H_ #define _PERSONIMPL_H_ #include < iostream > class CDate { }; class CAddress { }; class CPersonImpl /// 구현 부분. { public: CPersonImpl(const std::string& name, const CDate& birthday, const CAddress& address) : theName(name), theBirthDay(birthday), theAddress(address) { } std::string GetName() const { return theName; } CDate GetBirthday() const { return theBirthDay; } CAddress GetAddress() const { return theAddress; } private: std::string theName; CDate theBirthDay; CAddress theAddress; }; #endif
Person.h
#ifndef _PERSON_H_ #define _PERSON_H_ #include < string > #include < boost/tr1/memory.hpp > /// 인터페이스 구현에 필요한 전방 선언들. class CDate; class CAddress; class CPersonImpl; class CPerson /// 인터페이스 부분. { public: CPerson(const std::string& name, const CDate& birthday, const CAddress& address); ~CPerson(); std::string Name() const; CDate BirthDay() const; CAddress Address() const; private: /// 구현 부분에 대한 포인터. std::tr1::shared_ptr< CpersonImpl > m_pPersonImpl; }; #endif
Person.cpp
#include "Person.h" #include "PersonImpl.h" CPerson::CPerson(const std::string &name, const CDate &birthday, const CAddress &address) : m_pPersonImpl(new CPersonImpl(name, birthday, address)) { } CPerson::~CPerson() { } std::string CPerson::Name() const { return m_pPersonImpl->GetName(); } CDate CPerson::BirthDay() const { return m_pPersonImpl->GetBirthday(); } CAddress CPerson::Address() const { return m_pPersonImpl->GetAddress(); }
멤버 함수를 호출하면 구현부 객체의 데이터까지 가기 위해 포인터를 타야 함.
즉 한번 접근 할 때 마다 요구 되는
간접화 연산이 한 단계 더 증가.
객체 하나씩을 저장하는 데 필요한 메모리 크기에 구현부 포인터의 크기가 더 해짐.
구현부 포인터가 동적 할당된 구현부 객체를 가리키도록 어디선가 그 구현부 포인터의 초기화가 일어나야 함.
위와 같은 단점도 있지만, 컴파일의 의존도를 최대한 줄여서 컴파일 시간을 줄여 시간을 절약 할수 있음.
'[ Programming ]' 카테고리의 다른 글
인터페이스 상속과 구현 상속의 차이를 제대로 파악하고 구별하기. (0) | 2009.07.15 |
---|---|
상속된 이름을 숨기는 일은 피하자. (4) | 2009.07.05 |
전역 변수와 static 전역변수의 차이 (0) | 2009.06.14 |
변수 정의는 늦게 할수 있을 때 까지 (2) | 2009.06.14 |
const (0) | 2009.05.14 |