[완료] 클래스 멤버 함수 포인터에 관한 질문드립니다.
글쓴이: parkon / 작성시간: 화, 2012/02/07 - 12:15오전
요즘 제가 염치 없이 여기에 질문글을 많이 올리는 군요...,
하고 싶은 건 추상 클래스에서 구상 클래스의 멤버 함수 포인터를 인자로 받아 오는 건데요,
대충 코드를 써 보면
class Abstract { void Draw(double (*fcn)(double)) { // 이 함수 fcn에 해당하는 그림 그리는 루틴 } } class Concrete : public Abstract { double f1(double x); double f2(double x); //... void Draw1() { Draw(&Concrete::f1; } void Draw2() { Draw(&Concrete::f2; } //... }
이런 식을 원하는데 잘 안되는군요.
실제 문제는 위 보다 많이 복잡하고 제가 또 좌충우돌 하다보니
정확히는 말씀드리기 어렵지만
위처럼 했더니만
뭐 non-static member 함수는 주소를 받을 수 없다는 (?) 에러가 나오고
위의 Draw1을
typedef double (*fun)(double); void Draw1() { Draw(reinterpret_cast<fun>(&Concrete::f1); }
이렇게 바꾸니까
double (Concrete::*)(double)을 double (*)(double)로 바꾸려 한다는 warning이 뜨는군요.
제 고민에 조언 주시면 감사하겠습니다.
Forums:
저도 몰라서 해봤는데...
static 으로 주니까 되기는해요.
요기 참조 : http://cafe.naver.com/develx.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=144&
----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.
매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.
각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com
이건 방금전 사이트를 참조해서 만든거예요.
되기는 하지만. 설명은 못하겠네요. ㅇ_ㅇ;;;
출력결과
10.100000
10.200000
10.100000
10.200000
----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.
매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.
각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com
헉 고맙습니다. 일단 static으로 하는건 제 경우
헉 고맙습니다.
일단 static으로 하는건 제 경우 멤버 변수들을 마구 참조해야 하는 관계로 저한테는 안맞을것 같구요,
제 지식이 짧아 아직은 잘 모르겠지만
올리신 두번째 코드 보니까 일단 서광이 확 비치네요.
근데 저 OFFSET구문,플랫폼에 의존하겠지요 ?
이 의존성만 없앨수 있다면 금상첨화일텐데요,,,
음..
32비트 시스템에서 일반 함수 와 클래스의 정적 멤버 함수는 4바이트 포인터 값하나로 표현가능합니다.
하지만 클래스의 비정적 멤버함수의 경우 "오브젝트주소 + 비정적 멤버 함수 주소" 형태가 되어야 정상적인 포인터 값으로서 의미가 있습니다. 비정적 멤버 함수내부에서 클래스 멤버 변수를 참조하는 코드는 항숭 오브젝트의 주소를 알고 있어야 하기때문입니다.
따라서 다음과 같은 코드는
obj.funcA();
컴파일러가 funcA 멤버함수를 호출하기 위해 obj의 주소와 funcA 멤버함수의 주소 모두를 알고 있어야 호출가능합니다.
MyClass::funcA();
와 같은 함수호출코드는 컴파일러가 단순히 MyClass 네임스페이스의 funcA 함수 주소만 알고있어도 호출가능합니다.
따라서 ANSI C++ 에서는 비정적 멤버 함수의 주소를 포인터 변수에 저장할수 없습니다. 32비트 시스템에서 오브젝트 주소 + 함수 주소의 8바이트값을 4바이트 포인터 변수에 넣을수가 없기때문입니다.
볼랜드 계열 (지금 이름은 엠바카데로) C++ 컴파일러는 이러한 경우를 대비하여 멤버함수 포인터 타입을 제공합니다. 지금 잘 기억이 안나는데 32비트 시스템에서 8바이트 크기를 가집니다. 그리고 당연히 해당 포인터로 멤버함수를 호출할 수 있습니다. 키워드가 지금 기억이 안나는데, 찾아보시면 금방 아실수 있을겁니다.
따라서 원하시는 작업은 볼랜드사의 C++ builder 에서는 쉽게 가능합니다. MS 계열의 Visual C++ 에서는 일반적으로 할수 없고, 인라인 어셈블리 코드를 직접 작성하셔야 합니다. Visual C++ 의 ATL 소스를 parkon 님이 원하시는 작업을 하기 위해 썽킹이라는 기술을 사용합니다. 인라인어셈블리를 사용한 트릭인데요. 코드 프로젝트의 atl 기초강좌(몇개 안됩니다)를 찾아보시면 잘 기술되어 있는 강좌를 찾아 보실수 있습니다.
isson님 답변 감사합니다. 설명 듣고 보니 제가
isson님 답변 감사합니다.
설명 듣고 보니 제가 하려고 하는게 그렇게 쉽고 단순한 문제는 아닌듯 하군요.
(전 처음엔 아주 흔한 케이스이고, 그래서 아주 쉬운 해법이 있는데 무식한 저만 모르는 문제 정도로 여겼습니다.)
제 경우는 구현을 포기하는 한이 있더라도 플랫폼 의존성은 용서가 안되는 관계로
일단은 그대로 적용하기는 어렵겠네요.
그래도 덕분에 왜 non-static 멤버 함수의 포인터가 문제가 되는지는
이제 잘 이해했습니다.
어떻게 해야 할지 고민 좀 더해 봐야 겠습니다.
static_cast?
찾아보니 이런 얘기가 있네요.
http://stackoverflow.com/questions/4272909/is-it-safe-to-upcast-a-method-pointer-and-use-it-with-base-class-pointer/
jick님, 답변 고맙습니다. 아주 솔깃한
jick님, 답변 고맙습니다.
아주 솔깃한 해법이군요. 잘 될것같은 예감이... ^^
있다가 위 방법대로 해보고 제 결과를 올리도록 하겠습니다.
using namespace std; class
멤버 함수를 다른 곳에 대입하려면 먼저 멤버 함수를 this를 포함해 인자가 1개 더 추가된 일반 함수로 바꾸어주어야 합니다.
위 코드에서 mem_fun_1_t가 그런 일을 합니다.
그 후 binder1st를 사용해서 this를 바인드하여 다시 인자가 1개짜리인 함수로 만들었고 이를 std::function을 통해서 넘겨주었습니다.
그런데 위 클래스의 설계는 완전히 잘못되었습니다. 가상함수나 다형성을 조금 더 공부하시고 설계에 대해서 다시 한번 고민해보시는 것이 좋겠습니다.
힌트를 드리면 추상 클래스가 콘크리트의 구현을 알아야만 한다는 것이(함수 포인터를 대입해주기 때문) 이상한 부분입니다.
위 jick님 방법데로 (제 상황에 맞게 수정해서)
위 jick님 방법데로 (제 상황에 맞게 수정해서) 해 보니 컴파일도 런도 잘 됩니다.
많은 도움 되었습니다...^^
Windowsprogrammer님 조언 감사드립니다.
위 내용뿐만 아니라 프로젝트 전체적으로 클래스 설계가 얼키고 설키고 엉망인건 몸으로 절감하고 있지만
능력과 시간 부족으로... ^^
가르쳐 주신 방식과 조언은 시간을 두고 천천히 음미해봐야 겠습니다.
두분과 제 글에 관심을 보여주신 모든 분께 다시 한번 감사드립니다... 꾸뻑.
댓글 달기