본문 바로가기
프로그래밍 이야기/C++ 기초

[Design Pattern] PIMPL (Pointer to Implementation)

by Mulder5 2021. 2. 3.
반응형

엄밀히 Design Pattern은 아니지만 Bridge pattern과 비슷한 계층 개념인 PIMPL(Point to implementation)에 대해서 알아보자.

PIMPL의 장점

1. 컴파일 속도를 향상시킨다.
2. 완벽한 정보 은닉이 가능하다. 헤더 파일을 감출 수 있다.

이러한 개념을 예제를 통해 알아보자. 다음은 Point 클래스와 이에 대한 구현의 간단한 예이다.

// Point1.h

class Point
{
	int x, y;
public:
	Point(int a = 0, int b = 0);
	void Print() const;

};
// Point1.cpp

#include <iostream>
#include "Point1.h"

using namespace std;

Point::Point(int a, int b) :x(a), y(b) {}

void Point::Print() const
{
	cout << x << ", " << y << endl;
}
// Main.cpp

#include <iostream>
#include "Point1.h"

int main()
{
	Point p(1, 2);
	p.Print();
}

Point 클래스에 대한 header, cpp와 Main 파일로 구성되어있다. 이 예제에서 사용자의 요구나 개발자의 필요에 의해 Point에 기능을 추가해야  한다면 어떻게 해야할까? 아주 간단하게 다음과 같이 Point1.h에서 멤버 데이터를 추가 해줄 수 있겠다.

class Point
{
	int x, y;
	int debug; // 멤버 데이터의 추가 -> 컴파일 한다면? -> 이 파일을 include한 모든 파일이 리빌드가 된다. 
public:
	Point(int a = 0, int b = 0);
	void Print() const;

};

본 예제 안에서는 가장 간단한 구현 방법일 수 있으나 만약 이 클래스가 이미 많은 곳에서 사용중인 것이라면 이야기가 달라진다. 구현 자체는 간단했지만, Point1.h를 include한 모든 파일에서 다시 컴파일이 발생하므로 컴파일 시간이 굉장히 많이 늘어나게 된다. 이러한 문제를 해결할 수 있는 방법이 바로 PIMPL이다. 

PIMPL

위의 예제를 개선하기 위해서 PointImpl과 Main 사이에 하나의 계층을 추가한다. 

이 예제에서 PointImpl은 이전 예제에서 Point1을 대채한다. 

// PointImpl.h

class PointImpl
{
	int x, y;
	// 사용자 요구에 의해서 기능추가된다면?
	// 다시 컴파일 되는 대상은
	// PointImpl, Point2 뿐이다.
	int debug;
public:
	PointImpl(int a = 0, int b = 0);

	void Print() const;
};
// PointImpl.cpp

#include <iostream>
#include "PointImpl.h"

using namespace std;

PointImpl::PointImpl(int a, int b) :x(a), y(b) {}

void PointImpl::Print() const
{
	cout << x << ", " << y << endl;
}
// Point2.h

class PointImpl;

class Point
{
	PointImpl* pImpl;

public:
	Point(int a = 0, int b = 0);
	void Print() const;

};
// Point2.cpp

#include "PointImpl.h"
#include "Point2.h"

Point::Point(int a, int b)
{
	pImpl = new PointImpl(a, b);
}

void Point::Print() const
{
	pImpl->Print();
}
#include <iostream>
#include "Point1.h"

int main()
{
	Point p(1, 2);
	p.Print();
}

위 구현 내용은 아래의 그림과 같다. PointImpl.h 가 변경되더라도 다시 컴파일되는 범위는 PointImpl.cpp와 Point2.cpp로 재한된다. 게다가 이것을 라이브러리로 사용자에게 제공하는 경우, Point.h와 라이브러리 파일을 제공하면 되므로 PointImpl.h의 내용도 완전히 감출 수 있어 완전한 정보은닉의 장점이 한가지 더 있다. 

 

정리

PIMPL -> 중간계층의 추가 -> 컴파일 속도 빨라짐 -> 정보 은닉 효과

반응형

'프로그래밍 이야기 > C++ 기초' 카테고리의 다른 글

[Design Pattern] Container  (0) 2021.02.05
[Design Pattern] Observer (관찰자)  (0) 2021.02.04
[Design Pattern] Bridge  (0) 2021.02.02
[DesignPattern] Facade  (0) 2021.01.19
[C++]Design Pattern - STL과 Adapter  (0) 2020.12.30