2009-07-30 3 views
19

멤버 함수 포인터를 사용하여 가상 함수의 기본 클래스 구현을 호출하려고합니다. FUNC의 파생 클래스 구현 위 코드에서 함수 포인터가있는 가상 멤버 함수의 기본 클래스 정의를 호출합니다.

class Base { 
public: 
    virtual void func() { cout << "base" << endl; } 
}; 

class Derived: public Base { 
public: 
    void func() { cout << "derived" << endl; } 

    void callFunc() 
    { 
     void (Base::*fp)() = &Base::func; 
     (this->*fp)(); // Derived::func will be called. 
         // In my application I store the pointer for later use, 
         // so I can't simply do Base::func(). 
    } 
}; 

는 callFunc 호출한다. Base :: func를 가리키는 멤버 함수 포인터를 저장할 수있는 방법이 있습니까? 아니면 어떤 식 으로든 using을 사용해야합니까?

실제 응용 프로그램에서는 boost :: bind를 사용하여 callFunc에서 boost :: function 개체를 만들었습니다.이 개체는 나중에 내 프로그램의 다른 부분에서 func를 호출하는 데 사용됩니다. boost :: bind 또는 boost :: function에 도움이 될이 문제를 해결하는 방법이 있다면.

+0

가능한 복제본 [C++ : 가상 멤버 함수의 단일 형 버전에 대한 포인터?] (https://stackoverflow.com/questions/5064614/c-pointer-to-monomorphic-version-of-virtual-member-function) –

답변

11

참조 또는 포인터를 통해 가상 메서드를 호출하면 항상 파생 된 형식을 찾는 가상 호출 메커니즘이 활성화됩니다.

가장 좋은 방법은 가상이 아닌 대체 기능을 추가하는 것입니다.

0

함수 포인터를 통해이 작업을 수행해야하는 특별한 이유가 있습니까?

당신은 쓸 수 있어야 :

Base::func(); 

는 기본 클래스 구현을 호출 할 수 있습니다.

+1

나는 내 질문에 내가 callFunc에 포인터를 저장했지만 실제로 내 프로그램에서 다른 장소에서 func를 호출하는 데 사용합니다. –

+0

가상 함수의 경우에는 작동하지 않습니다. 항상 vtable 조회를 수행하고 파생 클래스에서 메소드를 호출합니다. – Joel

1

문제는 멤버 함수 포인터가 베어 함수 포인터와 완전히 같지 않다는 것입니다. 실제로 포인터 일뿐만 아니라 considerably more complex structure이며 컴파일러 구현 수준에서 세부 사항이 다릅니다. (this->*fp)() 구문을 통해 호출하면 실제로 원래 함수에서 호출되므로 가상 함수를 전달합니다.

작동하지 않을 수있는 한 가지 방법은 비 - 메소드 포인터 유형으로 변환하는 것입니다. 이것은 조금 삐걱 거리지만 나는 생각하면 그것이 작동합니다. 당신은 여전히 ​​Base *를 통과해야하지만 당신은 명시 적으로 수행하고, 가상 함수 파견 통과하여-입니다 :

typedef void BasePointer(Base*); 

void callFunc() 
{ 
    BasePointer fp = (BasePointer *)&Base::func; 
    fp(this); 
} 

업데이트 : 좋아, 아니, 당신이 그런 식으로 할 수 없습니다. 불법이며 합법적 인 경우 안전하지 않습니다. C++ FAQmore on this입니다. 그러나 그것이 당신의 문제를 해결하지 못한다는 것을 안다. 문제는 Base 포인터를 통해 Base::func을 호출하려는 경우 포인터를 가리키는 개체가 이고 인 개체는 Base이어야합니다. 이를 조정할 수 있으면 멤버 함수 포인터를 사용할 수 있습니다.

또 다른 생각이 있지만 꽤 좋지는 않지만 적어도 실행 가능합니다. 가상이 아닌 Derived에 함수를 제공하고 명시 적으로 Base::func을 호출합니다. 대신 그 지점을 가리 키십시오. funccallFunc의 다양한 변형의 일반적인 경우이 작업을 수행해야하는 경우 확장되지 않지만 한 가지 방법으로는 잘 작동합니다.

+1

가장 확실하게 _ 작동하지 않을 것입니다! 'sizeof (BasePointer)'와'sizeof (& Base :: func)'를 비교하십시오 : –

+0

mmutz : 그래. 나는 게시하기 전에 항상 테스트를 시도하고, 오늘 나는 나 자신을 할 시간을 남기지 않았다. * static_cast는 멤버 함수 포인터에서 함수 포인터 부분을 꺼내기에 충분히 똑똑 할 수 있었지만 함수의 파이썬 개념이 이제는 C++을 오버라이드하고 있습니다. :) – quark

+0

이것은 거짓입니다. "호출 할 함수의 주소뿐만 아니라 호출 할 개체의 주소도 함께 전달됩니다" –

0

쿼크가 말하는 것 외에도 일반적인 기능 포인터 대신 신호/슬롯 구현을 사용해야한다는 것이 일반적입니다. Boost에는 libsigc와 다른 것들이 있습니다.

2

불행히도 당신이하려는 것은 불가능합니다. 함수 포인터의 가상 기능을 유지하기 위해 포인터 - 구성원 - 기능은 으로 설계된입니다.

0

무엇이 문제입니까?

(Base(*this).*fp)(); 

이제는 만족 스럽다면 처음부터 함수 포인터를 사용하는 이유가 무엇인지에 대한 질문이 제기됩니다. 나는 좀 더 많은 맥락이 도움이 될 것이라고 생각한다.

+0

이것은 quark ("...베이스 포인터를 통해 Base :: func를 호출하려면 포인터가 가리키는 오브젝트도베이스 여야합니다.")에 의해 이미 제안되었습니다. Eddie가 함수를 호출 할 때 슬라이스 할 유형을 알고 있다고 보장 할 수 없다고 가정합니다. – Troubadour

관련 문제