在C ++中传递void(*)

时间:2009-11-29 16:01:58

标签: c++

我有一个std :: map,我正在尝试存储值的void指针。问题是,我试图存储的大部分指针都是类中的方法,并且具有不同数量的参数。我知道对于params我可以使用一个va列表,所以这不是一个问题,问题是实际的指针本身。

这就是我所拥有的:

class A 
{
public:
  A();
  void methodA(...);
};
class B
{
public:
  B();
  void methodB(...);
};
void method_no_class(...) { }

std::map<int, void(*)(...)> my_map;

my_map[0] = &method_no_class;
B* cb = new B();
my_map[1] = &cb->methodB; // will return error

6 个答案:

答案 0 :(得分:3)

也许这些信息可以帮到你:

http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.1

指向方法的指针与指向函数的指针的类型不同。如果您想将它们存储在单个集合中,则必须进行手动转换。

答案 1 :(得分:1)

干净的OO方式是定义命令接口。该接口将采用实例(AB)和所有参数。在invoke()方法中,它将调用实例的方法。

然后,您可以使用这些命令接口的映射(只需为它们定义一个定义抽象invoke()方法的公共子类)。编译器会为您检查所有类型和参数,您不必使用varargs。

答案 2 :(得分:0)

你应该在这里使用functionoids。它们可以用作具有不同签名的函数指针的灵活且类型安全的替代。需要一个抽象基类。它包含带有公共参数的实际函数调用,如果有的话。

class Functioniod: public YourClass {
    virtual void execute(char d, common_parameters,...) = 0
}

对于要使用的每个函数,都可以创建派生类。构造函数包含特定于函数的参数,而execute()函数包含实际调用。稍后调用此执行函数而不是函数指针。它需要在每个functionoid中具有相同的签名。当然,它也可以在任何其他类别中调用不同的东西。

class FuncA: public Functionoid {
    FuncA(int _a, float _b, string _c, function-specific-parameters...) {
        a = _a; b = _b; c = _c; 
    }
    void execute(char d, common-parameters,...) {
        call-to-member(d, a, b, c);
    }

    int a;
    float b;
    string c;
}

现在,如果你想用它来代替你的成员函数指针,你可以这样做:

std::map<int, *Functionoid> my_map;

my_map[0] = new FuncA(someInt, someFloat, someString);
my_map[1] = new FuncB(some-other-parameters...);

并使用

执行它们
my_map[0]->execute(common-parm);
my_map[1]->execute(common-parm);

答案 3 :(得分:0)

关于Kamil Szot的回答,C ++常见问题解答(和book)是对C ++和面向对象编程的深层次的一个很好的参考。第33节具体说明了您遇到的问题:

在C ++中,成员函数有一个指向对象的隐式参数(成员函数内的this指针)。普通的C函数可以被认为具有与成员函数不同的调用约定,因此它们的指针类型(指向成员函数的指针与指向函数的指针)是不同的并且不兼容。

当然,你问题的answer有点缺乏细节。

答案 4 :(得分:0)

您可能希望查看方法操作符 - &gt; ,:: 及其朋友。我会尝试找到更好的链接,但启动here

更新:希望this是方法指针和运算符的更好文章。

答案 5 :(得分:-1)

这是一个让您入门的示例代码。没有编译它,所以可能需要一些调整。

#define func(Instance,Method,Class) \
  (__int64(Instance)<<32 + __int64(&Class::Method))

#define invoke(Func,Method,Class) \
  invoke1(Func,(Class*)0)->*invoke2(Func,&Class::Method)

template<class Class>
Class* invoke1(__int64 Func,Class*)
{
  return (Class*)(int)(Func>>32);
}

template<class Method>
Method invoke2(__int64 Func,Method)
{
  return (Method)(int)Func;
}

------------ USAGE ------------
class B
{
  void methodB(int a,float b){}
};
std::map<int, __int64> my_map;

my_map[0] = func(cb,methodB,B);
invoke(my_map[0],methodB,B)(1,2.f);