c++는 java나 c#처럼 interface 키워드를 이용해서 인터페이스를 구현 하지는 않지만 virtual함수를 통해 인터페이스를 구현한다.
즉, 상속하고자 하는 Base class에 virtual 함수가 존재한다면 그 class를 상속해서 쓰는 쪽에서 virtual 함수를 마음껏 재정(override)의 해서 쓰면 된다는 의미이다.
(반대로 virtual이 아닌 일반 함수의 경우 override하지 말라는 뜻이다.)
이렇듯 virtual함수를 통해 인터페이스를 제공하는 것은 일반적이다. 그러나 무조건 virtual함수 만을 이용해서 인터페이스를 구현하다보니 몇가지 문제점이 있다.
1. 개발자의 확장을 위한 virtual함수인지 사용자가 override해서 사용하는 함수인지 모호해 진다.(즉, 내가 만든 class에 virtual함수가 존재하면 사용하는 사용자에게 이 class는 상속해서 사용하는게 아니라 interface만 제공할테니 기능만 적절히 사용하세요 라는 의미를 전달하기가 어렵다.)
2. 인터페이스 안에 공통적으로 사용되는 코드의 중복이 발생한다. (없을수도 있음)
예를 통해 다음과 같이 string을 전달받아서 xml, json등의 형태로 구성해서 리턴해주는 class를 구현하면서 위의 문제점을 해결하기 위해 NVI를 활용하면 된다.
- Base class로 Composer class를 만들고 사용자에게는 compose함수를 인터페이스로 제공한다.(사용자 입장에서는 공개된 인터페이스만 고려하면 된다.)
- Base가 되는 Composer에서 공통된 기능을 비가상 함수로 구현하고 composer각자가 재정의해서 사용해야 하는 기능은 private virtual함수로 구현해 둔다.
(개발자 입장에서는 확장성이 늘어나고 어떤 부분을 구현해야할지 명확해진다.) - XMLComposer와 JsonComposer class를 BaseComposer를 이용하여 기본 기능을 상속 받고 private virtual함수를 목적에 맞게 구현한다.
Composer Class
class Composer {
public:
std::string compose(std::string data) { //사용자에게 compose 기능을 제공하는 인터페이스
//공통적으로 사용되는 code삽입 가능
std::string result = doCompose(data); //virtual 함수 호출
//공통적으로 사용되는 code삽입 가능
return result;
}
bool isComposabe (std::string data) { //공통 기능의 예
return true;
}
private:
virtual std::string doCompose(std::string data) = 0; //개발자에게 확장성을 주는 private virtual 함수
};
XMLComposer Class
class XMLComposer : public Composer {
private:
virtual std::string doCompose(std::string data) {
// make XML
std::string result;
cout<<"make xml"<<endl;
return result;
}
};
JSONComposer Class
class JSONComposer : public Composer {
private:
virtual std::string doCompose(std::string data) {
// make JSON
std::string result;
cout<<"make json"<<endl;
return result;
}
};
다음과 같이 비가상 인터페이스를 통해 서로다른 확장성 있는 구현이 가능해진다.
int main(void){
Composer * pXML = new XMLComposer();
pXML->compose("test");
Composer * pJson = new JSONComposer();
pJson->compose("test2");
return 0;
}
'C and C++' 카테고리의 다른 글
[C++] 상속에 대해 (0) | 2018.09.01 |
---|---|
[C++] 상속받은 비가상 함수를 재정의(override)하면 안된다. (0) | 2018.08.19 |
[C++] pImpl(pointer to implementation)를 이용해서 인터페이스와 구현을 분리하기 (0) | 2018.08.05 |
[C++] C++ 스타일의 캐스트 (0) | 2018.07.25 |
[C++] 클래스를 캡슐화(Encapsulation) 하는 이유(왜 멤버변수는 대부분 private인가?) (1) | 2018.07.18 |