정의되지 않은 클래스 맴버 함수 호출하기

당연이 인스턴스로 생성된 클래스의 맴버함수를 호출하기 위해서는 해당 클래스를 정의하고 있는 헤더 파일을 포함해야 하지만, 헤더 파일을 포함하지 않고 클래스의 맴버함수를 호출해야할 경우가 있다. 즉 정의되지 않는 클래스 인스턴스의 맴버 함수를 호출해야한다.

어떻게 할 수 있을까? 해답은 클래스 맴버 함수 포인터를 사용하는 방법이다.

먼저 사용하는 코드부분에서 호출해야하는 클래스를 선언하고 그 클래스에서 사용해야할 맴버 함수의 포인터를 선언한다.

C사용하는클래스의 헤더파일에…

class C사용될클래스;
typedef void (C사용될클래스::*맴버함수)(void);

그리고 C사용하는클래스의 맴버변수로써 C사용될클래스의 인스턴스와 맴버함수에 대한 변수를 추가한다.

private:
    맴버함수 funcPtr;
    C사용될클래스* p사용될클래스인스턴스;

public:
    void Set(맴버함수 funcPtr, C사용될클래스* pInstance) {
        this.funcPtr = funcPtr;
        p사용될클래스인스턴스 = pInstance;
}

이제 실제로 C사용될클래스의 멤버함수를 사용하는 방법은 아래와 같다.

((*p사용될클래스인스턴스).*funcPtr)();

여기서 주목할 것은 앞에서도 언급했지만 어디서도 C사용될클래스에 대한 헤더파일을 포함하지 않았다는 점이다. 즉, C사용하는클래스는 단지 C사용할클래스를 모르며, 단지 C사용할클래스에서 꼭 필요한 것만 알고 있다는 것이다.

꼼꼼한 독자라면 직감했겠지만, C사용하는클래스의 funcPtr과 p사용될클래스인스턴스는 어떤식으로 값을 설정해야하는가라는 문제가 생긴다.

이것은 C사용될클래스에서 C사용할클래스의 Set함수를 호출해주면 된다. 즉 C사용될클래스의 정의부 어디에선가 다음과 같은 형식의 코드(한가지 예일뿐..)를 호출한다.

p사용하는클래스 = new C사용하는클래스();
p사용하는클래스->Set(&C사용될클래스::Function, this);

사실, 이런 기술(정확히, 솔직이 말한다면 편법)이 필요한 이유는 두개의 클래스가 서로 상호참조를 하는 경우이다. 이런 경우는 서로의 헤더파일을 포함해서 쉽게 구현할 수 있는 경우가 대부분이지만, 만약…. 이 두개의 클래스가 서로 완전이 다른 개념의 개발 프로젝트인 경우에는 예외인데, 예를 들어서 하나의 클래스는 ATL 프로젝트에 있고, 다른 하나는 일반적인 Generic C/C++ 프로젝트인 경우, 단순이 헤더파일을 포함할 경우 서로의 개발환경을 이해하지 못하므로 엄청나게 많은 에러 메세지를 쏟아 낼 것이고, 머리속이 하얗게  되는 것을 경험할 것이다. 이 편법을 사용하지 않는 것이 제대로 개발하고 있다는 증거인지라, 사용하지 않기를 바라지만 꼭 필요한 경우라면 요긴할 것으로 판단되어 글로 정리하여 남긴다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다