如何在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);
问题是 - MYSTERYTYPE应该是什么?尽管值<!> amp; A :: b如果通过printf输出它就打印得很好。
澄清:是的,<!> amp; A :: b是在C ++下定义的。是的,我正试图获得班级成员的抵消。是的,我很狡猾。
编辑:哦,我可以使用offsetof()。不管怎样,谢谢。
解决方案
您有一个指向两个不相关类的数据成员指针。好吧,你找不到一个可以同时拥有两个指针的常见类型。它只有在函数参数是指向派生成员的数据成员指针时才有效,因为它保证包含成员,如果基数包含它:
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! */ }
如果以上内容有效,你真的会搞砸了。以上不有效,因为从e
到b
的转换不是隐含的。如您所见,我们分配了一个指向b :: c的指针,然后我们可以使用一个根本不包含它的类取消引用它! (a
)。编译器强制执行此顺序:
int main() { int b::*d = &b::c; e e_; (e_.*d) = 10; /* bug! */ }
它失败现在编译,因为<=>不是从<=>派生的,成员指针指针所属的类。好!但是,以下内容非常有效并且编译,当然(更改了类<=>和<=>):
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
或C
对象内的整数的地址来调用函数?在这种情况下,Jeff McGlynn的回答是要走的路。
否则,如果你真的想要做一些棘手的事情,需要C ++的奇怪的指针到成员设施(你几乎肯定不是):
由于类<=>和<=>不相关,因此您需要一个模板函数来处理这两个:
template <typename T>
void DoThings(int T::*x);
如果<=>实际上是从<=>派生的,那么以下内容将起作用:
void DoThings(int A::*x);
<!> amp; A :: b和<!> amp; C :: d是无意义的,没有相关联的地址。您是否想要获得会员的抵消?
您确定不想要以下内容吗?
DoSomething(&obj_a,&obj_a.b);
如果您使用模板作为j_random_hacker建议,并且编译器在您调用函数的位置知道每个类的类型,则问题的字面答案是<!> quot; template <typename CLASS> void DoThings (CLASS * object, int CLASS::*MEMBER)
<!> quot;。
以下是它如何适合您的示例:
#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;
}