C ++의 일반 유형에 대한 멤버 변수 포인터를 캐스트하는 방법
-
05-07-2019 - |
문제
내 응용 프로그램에서 이와 유사한 코드가 있습니다.
class A
{
public: int b;
}
class C
{
public: int d;
}
void DoThings (void *arg1, MYSTERYTYPE arg2);
A obj_a;
C obj_c;
DoThings(&obj_a, &A::b);
DoThings(&obj_c, &C::d);
문제는 - 미스터리 유형은 무엇입니까? void* 또는 int 작동은 값에도 불구하고 인쇄 된 경우 인쇄 된 경우에도 잘 인쇄됩니다.
설명 : 예, & A :: B는 C ++에 따라 정의됩니다. 예, 나는 클래스 멤버에게 오프셋을 얻으려고 노력하고 있습니다. 예, 나는 까다 롭습니다.
편집 : 오, 오프셋 ()를 사용할 수 있습니다. 어쨌든 감사합니다.
해결책
두 개의 관련없는 클래스에 대한 데이터 멤버 포인터가 있습니다. 글쎄, 당신은 두 포인터를 모두 잡을 수있는 일반적인 유형을 찾을 수 없습니다. 함수 매개 변수가 파생의 멤버에 대한 데이터 멤버 포인터 인 경우에만 작동합니다.베이스에 포함 된 경우 멤버도 포함 할 수 있기 때문입니다.
struct a { int c; }; struct b : a { }; int main() { int b::*d = &a::c; }
업데이트: 위의 변환이 왜 a::*
에게 b::*
암시 적으로. 결국, 우리는 보통 가지고 있습니다 b*
에게 a*
! 고려하다:
struct a { };
struct b : a { int c; };
struct e : a { };
int main() { int a::*d = &b::c; e e_; (e_.*d) = 10; /* oops! */ }
위의 유효가 있으면 실제로 많이 망칠 것입니다. 위의 것입니다 ~ 아니다 전환하기 때문에 유효합니다 b::*
에게 a::*
암시 적이 아닙니다. 보시다시피, 우리는 B :: C에 포인터를 할당 한 다음 전혀 포함하지 않는 클래스를 사용하여 피할 수있었습니다! (e
). 컴파일러는이 순서를 시행합니다.
int main() { int b::*d = &b::c; e e_; (e_.*d) = 10; /* bug! */ }
그것 실패합니다 왜냐하면 지금 컴파일하기 때문입니다 e
파생되지 않습니다 b
, 멤버 포인터 포인터가 속한 클래스. 좋은! 그러나 다음은 매우 유효하며 물론 컴파일됩니다 (변경된 클래스 a
그리고 b
):
struct a { int c; };
struct b : a { };
struct e : a { };
int main() { int e::*d = &a::c; e e_; (e_.*d) = 10; /* works! */ }
케이스에서 작동하려면 기능을 템플릿으로 만들어야합니다.
template<typename Class>
void DoThings (int Class::*arg) { /* do something with arg... */ }
이제 컴파일러는 주어진 멤버 포인터가 속한 올바른 클래스를 자동으로 배치합니다. 실제로 사용하려면 멤버 포인터와 함께 인스턴스를 전달해야합니다.
template<typename Class>
void DoThings (Class & t, int Class::*arg) {
/* do something with arg... */
(t.*arg) = 10;
}
Dothings를 작성할 때 이미 알고있는 멤버를 설정하려면 다음과 같습니다.
template<typename Class>
void DoThings (Class & t) {
t.c = 10;
}
다른 팁
당신은 단순히 내부에 사는 정수의 주소로 함수를 호출하려고합니까? A
또는 a C
물체? 이 경우 Jeff McGlynn의 대답은 갈 길입니다.
그렇지 않으면, C ++의 이상한 포인터 투 선원 시설을 요구하는 까다로운 일을하려고한다면 (거의 확실하지 않습니다).
수업 이후 A
그리고 C
관련이 없으므로 두 가지 모두 처리하려면 템플릿 기능이 필요합니다.
template <typename T>
void DoThings(int T::*x);
만약에 C
실제로 파생되었습니다 A
, 다음은 작동합니다.
void DoThings(int A::*x);
& a :: b 및 & c :: d는 무의미하며 관련 주소는 없습니다. 회원의 오프셋을 얻으려고합니까?
다음과 같은 것을 원하지 않습니까?
DoSomething(&obj_a,&obj_a.b);
j_random_hacker가 제안한대로 템플릿을 사용하고 컴파일러가 기능을 호출하는 지점에서 각 클래스의 유형을 알고 있다면 질문에 대한 문자 그대로의 대답은 "입니다."template <typename CLASS> void DoThings (CLASS * object, int CLASS::*MEMBER)
".
예제에 맞는 방법은 다음과 같습니다.
#include <iostream>
class A {
public:
int b;
};
class C {
public:
int d;
};
template <typename CLASS>
void DoThings (CLASS * object, int CLASS::*MEMBER)
{
std::cout << object->*MEMBER << std::endl;
}
A obj_a = { 2 };
C obj_c = { 4 };
int main (int argc, const char * argv[])
{
DoThings(&obj_a, &A::b);
DoThings(&obj_c, &C::d);
return 0;
}