pImpl 방식을 활용해서 인터페이스와 구현을 분리할 수 있다. 그러면 왜 인터페이스와 구현을 분리 해야할까?
여러가지 이유가 있겠지만 우선 헤더파일 안에 다른 헤더파일의 포함을 최소화 할 수 있어 컴파일 의존성을 최소화 할 수 있고(그러다보면 빌드 시간도 절약), 인터페이스와 구현내용간의 결합도가 떨어져서 유지보수에도 쉽다.
우선 인터페이스와 구현의 분리 개념의 예를 그림으로 보면 인터페이스 객체는 PhoneBook 관련해서 사용하는 쪽에 인터페이스를 제공하는 역할을 하는 class와 실제 그 기능이 구현되어 있는 역할을 하는 class로 나뉘게 된다. pImpl기법을 사용하면 하나의 기능을 제공하기 위해서는 아래와 같이 객체가 두개생성되는 비용이 발생하긴 한다.
간단하게 정리하면 실제 구현은 뒤로 숨기고 구현class(PhoneBookImpl)의 객체를 이용해서 인터페이스 역할은 하는 class(PhoneBook)가 구현 객체를 감싼다(wrapping).
코드를 보면 다음과 같다
<PhoneBook.hpp>
//인터페이스 역할을 하는 class
#ifndef PhoneBook_hpp
#define PhoneBook_hpp
#include <string>
class PhoneBookImpl;//PhoneBookImpl을 include하지 않기 위한 전방선언
class PhoneBook {
private:
std::shared_ptr<PhoneBookImpl> pImpl; //PhoneBookImpl객체의 delete를 신경쓰지 않기 위해 스마트 포인터를 이용
public:
PhoneBook(std::string name, std::string addr, std::string phoneNum);
std::string interfaceGetAddress();
std::string interfaceGetName();
std::string interfaceGetPhoneNum();
};
#endif /* PhoneBook_hpp */
<PhoneBook.cpp>
#include "PhoneBook.hpp"
#include "PhoneBookImpl.hpp"
PhoneBook::PhoneBook(std::string name, std::string addr, std::string phoneNum):
pImpl(new PhoneBookImpl(name, addr, phoneNum))
{ }
std::string PhoneBook::interfaceGetAddress() {
return pImpl->getAddress();
}
std::string PhoneBook::interfaceGetName() {
return pImpl->getPhoneNum();
}
std::string PhoneBook::interfaceGetPhoneNum() {
return pImpl->getPhoneNum();
}
<PhoneBookImpl.hpp>
#ifndef PhoneBookImpl_hpp
#define PhoneBookImpl_hpp
#include<string>
class PhoneBookImpl {
private:
std::string address;
std::string name;
std::string phoneNum;
public:
PhoneBookImpl(std::string name, std::string addr, std::string phoneNum);
std::string getName();
std::string getAddress();
std::string getPhoneNum();
};
#endif /* PhoneBookImpl_hpp */
<PhoneBookImpl.cpp>
#include "PhoneBookImpl.hpp"
PhoneBookImpl::PhoneBookImpl(std::string name, std::string addr, std::string phoneNum) :
name(name),
address(addr),
phoneNum(phoneNum)
{}
std::string PhoneBookImpl::getName() {
return name;
}
std::string PhoneBookImpl::getAddress() {
return address;
}
std::string PhoneBookImpl::getPhoneNum() {
return phoneNum;
}
'C and C++' 카테고리의 다른 글
[C++] 상속받은 비가상 함수를 재정의(override)하면 안된다. (0) | 2018.08.19 |
---|---|
[C++] NVI (non-virtual interface) idiom 비가상 인터페이스에 대해 (0) | 2018.08.11 |
[C++] C++ 스타일의 캐스트 (0) | 2018.07.25 |
[C++] 클래스를 캡슐화(Encapsulation) 하는 이유(왜 멤버변수는 대부분 private인가?) (1) | 2018.07.18 |
[C++] 객체의 값을 전달할때 복사 비용을 줄이는 방법 "상수객체 참조자" (0) | 2018.07.10 |