잉여력이 넘쳐나서 저런 쓸데없는 걸 만들어 봤는데
(메시지 - 메시지 핸들러 함수) 쌍을 HashMap으로 객체 내에 저장하고 wndProc()에서 적절히 찾아내서 메시지핸들러를 실행시키는 거...
클래스 하나에서는 잘 돌아가고, Derived 클래스에서 메시지핸들러를 overriding해도 잘 돌아가지만
Derived 클래스에서 처음으로 (메시지 - 메시지 핸들러 함수) 쌍을 추가하는 경우가 문제...
typedef int A::*MSGHANDLER (int arg);
class A {
CALLBACK wndProc(int msg); // 이놈이 적절히 msghandler를 골라서 실행한다.
void addMsgHndlr(int msg, MSGHANDLER mh); // hashmap에다 (msg-msghandler) 쌍을 저장
MSGHANDLER getMsgHndlr(int msg); // hashmap에서 msghandler를 읽어온다
virtual int onSize(int arg); // sample msgHandler
};
A::wndProc(int msg) {
return (this->*(getMsgHndlr(msg)))(arg); <i>// 이게 잘 되면 B::wndProc()을 다시 쓸 필요가 없을 텐데...</i>
}
class B : public virtual A {
virtual int onSize(int arg); // A::onSize()를 overriding. 적절히 동작한다.
int onDestroy(int arg); // A에 등록했던 적이 없는 새로운 msghandler.
};
A a; B b;
a.addMsgHndlr(WM_SIZE, &A::onSize)); // ok
b.addMsgHndlr(WM_NCDESTROY, reinterpret_cast<MSGHANDLER>(&B::onDestroy)); // epic fail. 실행은 되지만 wndProc()에서 segfault
-----------
addMsgHndlr에 인수를 추가해서 msghandler의 owner를 추가로 기록하면서
B::wndproc을 overriding하고 owner가 아니면 다시 A::wndproc을 부르게 하면 될 것도 같지만
그러면 이짓을 하는 의미가 없음.
저장하려면 실제로 호출하게 될 객체도 같이 저장해야지
그 객체가 this라 필요 없지 않나...?
아 맵이 객체 내에 있는거였구나. reinterpret_cast가 문제일것 같다. A::onDestroy랑 B::onDestroy는 사람이 볼때는 같은 함수 같아도 함수 포인터 자체가 완전 달라져
개념은 충분한 것 같으니 머리싸매고 고민하는것보다 남들이 고민해서 만들어놓은걸 분석하는게 더 빠를 것 같다. signal-slot 으로 한번 찾아봐 Qt에도 구현되어있고 boost::signal도 괜찮다
함수포인터 MSGHANDLER가 [hi_dword][low_dword] 이렇게 돼 있고 hi_dword가 class 시작부분, low_dword가 offset, reinterpret_cast하면서 hi_dword가 바뀌어버리는 거 아닌가 싶은데 그거 아니면 저게 실행이 안 되는 게 설명이 안 됨... cast에서 값이 바뀌는 부분이 전혀 없다면 A::wndproc()에서 실행되더라도 this가 B class 객체면 B::onDestroy()가 실행돼야 하기 때문에...
오우 이걸 memcpy로 해결한 용자가 있었군...ㅋㅋㅋ
http://dlunch.net/blog/using-member-function-pointer-in-cpp/