그래서 저는 최근에 멤버 함수 데이터에 대한 포인터를 저장하는 기능을 추가 한 변형 클래스가 있습니다. 다음 코드를 사용하여이를 수행합니다.member-function-pointer 잘못된 해킹에 대한 대안?
class Variant
{
void* _value;
template <typename T1>
void Variant::ThisCall(T1* pThis)
{
typedef void(T1::* fptr)();
fptr a;
int* iiVal = new (&a) int;
*iiVal = *((int*)_value);
(pThis->*a)();
}
};
// usage
Variant myfunc = &SomeClass::SomeMethod;
SomeClass* s = new SomeClass();
myfunc.ThisCall(s);
이 솔루션에서 가장 큰 점은 멤버 함수 포인터를 void *로 캐스트 할 수 없다는 것입니다. 따라서 대입 연산자는 대개이 연산의 역함수를 수행합니다. 주어진 데이터를 가져 와서 int 포인터 (포인터 자체 인 경우)로 마스크하고 int 포인터를 void *에 할당합니다. 이것은 완벽하게 유효합니다.
내 질문은 다음과 같습니다. 왜 이것이 문제에 대한 끔찍한 해결책이라고 생각합니까? 나는 이것이 몇 가지 심각한 문제가 될만한 큰 해킹 인 것처럼 느낀다. 그러나 나는 과거를 볼 수 없기 때문에 며칠 동안이 문제에 깊이 빠져 있었다. 감사!
[EDIT # 1]
한 주석이 가상 방식으로 작동하지 않을 수도 있다는 것을 유의. 나는 다음 코드를 사용하여 테스트했으며 체크 아웃 한 것으로 보인다.
class ImplA : public Base
{
public:
virtual void Print()
{
cout << "ImplA print\n";
}
};
class ImplB : public Base
{
public:
virtual void Print()
{
cout << "ImplB print\n";
}
};
class ImplC : public ImplA
{
public:
virtual void Print()
{
cout << "ImplC print\n";
}
};
// usage
Variant x = &Base::Print;
auto b = new ImplA; // replace ImplA with ImplB or ImplC and it works as expected
x.ThisCall(b);
몇 가지 추가 정보를 보려면 VS2010을 제 컴파일러로 사용하고 있습니다. 감사!
[편집 # 2]
이 컨텍스트를 제공하기 위해, 내가 지금하는 동안 짧은이 변형 클래스에 노력하고있다 그리고 당신이 그것에 던질 수있는 것을 지원하기 위해 노력하고 있습니다. 이렇게, 나는 함수 포인터 및 멤버 함수 포인터에 대해 생각했다. 그런 다음이 솔루션을 실제로 생각해 냈습니다. 캐스팅과 구문은 나를위한 첫 번째 붉은 깃발 이었지만, 그것이 보유하고있는 데이터의 분산 때문에, 영토와 함께 온다고 생각했습니다. 그러나 이것이 아직도 어떻게 작동하는지 확신 할 수 없습니다.
* 한 가지 문제 : * [가상 멤버 함수에 대한 포인터] (http://coliru.stacked-crooked.com/a/4691b73521b8145e)와 함께 작동하지 않을 가능성이 있습니다. 'void *'는 * 어떤 * 함수 포인터 IIRC와 같은 크기를 가질 필요는 없다. – dyp
IIRC 캐스팅 함수 포인터가 유효하지 않으며 UB로 연결됩니다. – RedX
@DyP : 방금 가상 멤버 함수를 확인했는데 제대로 작동합니다. 나는 그걸 증명할 때 사용했던 코드를 게시 할 것이다. 그래도 고마워! –