如何在C ++中将成员变量指针转换为泛型类型

时间:2009-01-07 15:29:18

标签: c++ class pointers member-pointers

我的应用程序中的代码与此类似:

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应该是什么?尽管如果你通过printf输出它并且打印出来的价值& A :: b就好了,那么无论是*还是int都没有工作。

澄清:是的,& A :: b是在C ++下定义的。是的,我正试图获得班级成员的抵消。是的,我很狡猾。

编辑:哦,我可以使用offsetof()。不管怎样,谢谢。

4 个答案:

答案 0 :(得分:6)

您有一个指向两个不相关类的数据成员指针。好吧,你找不到一个可以同时拥有两个指针的常见类型。它只有在函数参数是指向派生成员的数据成员指针时才有效,因为它保证包含成员,如果基数包含它:

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派生的,成员指针指针所属的类。好!但是,以下内容非常有效并且编译(当前更改了类ab):

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;
}

答案 1 :(得分:2)

您是否只是尝试使用恰好位于AC对象内的整数的地址来调用函数?在这种情况下,Jeff McGlynn的回答是要走的路。

否则,如果你真的想要做一些棘手的事情,需要C ++的奇怪的指针到成员设施(你几乎肯定不是):

由于类AC不相关,因此您需要一个模板函数来处理这两个:

template <typename T>
void DoThings(int T::*x);

如果C实际上来自A,则可以使用以下内容:

void DoThings(int A::*x);

答案 2 :(得分:0)

&amp; A :: b和&amp; C :: d是荒谬的,没有相关联的地址。您是否想要获得会员的抵消?

您确定不想要以下内容吗?

DoSomething(&obj_a,&obj_a.b);

答案 3 :(得分:0)

如果您使用模板作为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;
}