함수 포인터를 사용하여 가상 멤버 함수의 기본 클래스 정의 호출
-
05-07-2019 - |
문제
멤버 함수 포인터를 사용하여 가상 함수의 기본 클래스 구현을 호출하고 싶습니다.
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().
}
};
위의 코드에서 func의 파생 클래스 구현은 callFunc에서 호출됩니다.Base::func를 가리키는 멤버 함수 포인터를 저장할 수 있는 방법이 있습니까? 아니면 이를 사용해야 합니까? using
어떤 면에서는?
내 실제 응용 프로그램에서는 Boost::bind를 사용하여 callFunc에 Boost::function 객체를 생성하고 나중에 내 프로그램의 다른 부분에서 func를 호출하는 데 사용합니다.따라서 Boost::bind 또는 Boost::function이 이 문제를 해결하는 방법이 있다면 도움이 될 것입니다.
해결책
참조 또는 포인터를 통해 가상 메소드를 호출하면 항상 가장 파생 된 유형을 찾는 가상 통화 메커니즘을 활성화합니다.
가장 좋은 방법은 가상이 아닌 대체 기능을 추가하는 것입니다.
다른 팁
불행히도 당신이하는 일은 불가능합니다. 포인터 투 선원 기능입니다 설계 기능의 가상을 유지합니다.
문제는 멤버 함수 포인터가 기본 함수 포인터와 완전히 동일하지 않다는 것입니다.실제로는 단순한 포인터가 아니라 훨씬 더 복잡한 구조, 이는 컴파일러 구현 수준에서 세부 사항이 다릅니다.구문을 통해 호출하면 (this->*fp)()
실제로 원래 객체에서 호출하고 있으며 이로 인해 가상 함수 디스패치가 발생합니다.
작동할 수 있는 한 가지 방법은 메서드가 아닌 포인터 유형으로 캐스팅하는 것입니다.좀 삐걱거리긴 하지만 난 생각하다 작동해야합니다.당신은 여전히 통과해야 Base *
그러나 이를 명시적으로 수행하면 가상 함수 디스패치가 우회됩니다.
typedef void BasePointer(Base*);
void callFunc()
{
BasePointer fp = (BasePointer *)&Base::func;
fp(this);
}
업데이트: 알았어, 아니, 그렇게 하면 안 돼.불법이고, 합법이라면 안전하지 않을 것입니다.그만큼 C++ FAQ 가지다 이것에 대해 더 자세히.그러나 그것을 아는 것만으로는 문제가 해결되지 않습니다.문제는 호출하려는 경우 객체에 대한 포인터 또는 멤버에 대한 포인터라는 것입니다. Base::func
통해 Base
포인터가 가리키는 개체는 다음과 같아야 합니다. 또한 가 되다 Base
.이를 정렬할 수 있으면 멤버 함수 포인터를 사용할 수 있습니다.
예쁘지는 않지만 적어도 실행 가능한 또 다른 생각이 있습니다.에서 기능을 제공하세요. Derived
, 비가상, 명시적으로 호출 Base::func
.대신에 그것을 지적하십시오.다양한 변형이 있는 일반적인 경우에 이 작업을 수행해야 하는 경우 확장되지 않습니다. func
그리고 callFunc
하지만 한 가지 방법으로는 잘 작동합니다.
함수 포인터를 통해이 작업을 수행 할 특정 이유가 있습니까?
당신은 그냥 쓸 수 있어야합니다.
Base::func();
기본 클래스 구현을 호출합니다.
Quark의 말 외에도 더 일반적인 언급은 베어 함수 포인터가 아닌 신호/슬롯 구현을 사용해야한다는 것입니다. 부스트에는 하나가 있습니다. libsigc와 다른 많은 사람들이 있습니다.
이것에 무슨 문제가 있습니까?
(Base(*this).*fp)();
이제 만족한다면 왜 기능 포인터를 사용하고 있는지에 대한 의문이 제기됩니다. 더 많은 맥락이 도움이 될 것이라고 생각합니다.