방프리

17.12.11. Effective C++ 5. 구현 (항목31) 본문

C++/Effective C++

17.12.11. Effective C++ 5. 구현 (항목31)

방프리 2020. 1. 17. 00:59

항목 31 : 파일 사이의 컴파일 의존성을 최대로 줄이자

 

C++로 코딩을 하면서 기초로 배우는 것이 바로 #include란 키워드 입니다.

.h파일을 포함함으로써 헤더파일 안에 있는 클래스의 정의나 구현부를 컴파일할 때 불러오는 역할을 하는 키워드인데요.

이번 항목에서는 #include 의 사용을 줄이자? 라고 할 수 있겠네요.

C++의 클래스 정의는 클래스 인터페이스 뿐만 아니라 세부 구현 사항까지 많은 부분을 다루고 있습니다.

예를 들어 MMORPG게임의 경우엔 User 클래스 안에 수 많은 변수와 구현 함수들이 존재하죠.

(기존 3~4만줄은 그냥 뛰어 넘는다고 보시면 됩니다.) 

이렇게 수많은 작업을 처리하는 클래스에서 일을 하려면 같이 작업 해야하는 수 많은 클래스들을 User 클래스는

알아야 하기 때문에 전부 include 해주는 수밖에 없습니다.

즉.... 이런 혼종을 탄생시키고야 말죠

 

ex 1)

#include<string>

#include "Inventory.h"

#include "Monster.h"

#include.....

 

class User

{

// do Something

};

 

이렇게 짠들 문제만 없다면 상관 없습니다만... 컴파일 시간을 따져보면 정말 불합리하고, 

 

멍청한 짓이라 할 수 있겠습니다. 그래서 필자가 소개한 방법이 바로 전방 선언입니다.

ex2)

#include<string>

class Inventory;

class Monster;

 

class User

{

Inventory* inv;

Monster* mon;

};

 

전방 선언을 사용했으니 컴파일러가 굳이 구현부까지 들어가서 컴파일 할 필요가 없고, 

실제 객체였으면 세부내용까지 알아야 하나 포인터로 접근하기 때문에 구현부를 감출 수 있습니다.

그래서 필자가 제시한 것이 바로 구현을 맡은 클래스를 따로 두는 것입니다.

ex3)

#include <string>

 

class UserImpl; // User의 구현 클래스에 대한 전방선언

 

class Inventory;

class Monster;

 

class User

{

//do Something

};

이 방법을 '정의부에 대한 의존성'을 '선언부에 대한 의존성'으로 바꾸는 것이라고 합니다.

즉, 구현부 클래스와 선언부 클래스를 따로 두자는 것입니다.

가장 쉽게 이해하려면 가상함수를 예로 들면 될 것 같습니다.

ex4) 

class User

{

public :

virtual ~User();

 

virtual std::string name() const = 0;

virtual std::string birthDate() const = 0;

virtual std::string address() const = 0;

}; //선언부 클래스

하지만 이 방법을 따지고 들어가면 연산 부분에서는 굉장히 손해입니다.

구현부에 접근할 때마다 선언부 포인터에 접근하고 이리저리 타야하기 때문이죠

하지만 확장성이나 앞의 미래를 생각한다면?... 이 정도 연산은 감수해야한다고

필자는 어필하고 있습니다. 선택은 개발자의 몫이겠죠?

 

이것만은 잊지 말자!

* 컴파일 의존성을 최소화 하는 작업의 배경이 되는 가장 기본적인 아이디어는 '정의' 대신에

'선언'에 의존하게 만들자는 것입니다. 이 아이디어에 기반한 두 가지 접근 방법은 핸들 클래스와

인터페이스 클래스입니다.

* 라이브러리 헤더는 그 자체로 모든 것을 갖추어야 하며 선언부만 갖고 있는 형태여야 합니다.

이 규칙은 템플릿이 쓰이거나 쓰이지 않거나 동일하게 적용합시다.

 

Comments