C ++将struct函数作为继承结构中函数的参数传递

时间:2016-03-20 05:02:39

标签: c++ struct parameter-passing

我有两个结构,struct B继承自struct A.我想将一个函数作为参数从struct B传递给struct A以供struct A使用。

这是我想要实现的一个例子以及我遇到的问题,完整的代码将是TL; DR。

struct A
{
    int32 mynum;

    void Tick(float delta, bool doThis, void (funcparam)(float, bool, int32))
    {
        funcparam(delta, doThis, mynum);
    }
};
struct B : public A
{
    void RunThis(float deltaTime, bool doIt, int32 which)
    {
        // do something when called by Struct A
    };

    void DoSomething()
    {
        Tick(0.1f, true, &B::RunThis);
    };
};

问题在于这一行:来自函数Tick(0.1f, true, &B::RunThis);的{​​{1}},除非我从一开始就做错了,但我想我错了它,因为它仍然在标题内我目前正在定义的结构?

错误(我修改了错误以适应我的例子,我不认为我搞砸了......):

void DoSomething()

当然,从error C2664: 'void A::Tick(float,bool,void (__cdecl *)(float,bool))': cannot convert argument 3 from 'void (__cdecl B::* )(float,bool)' to 'void (__cdecl *)(float,bool)'省略B::并没有解决任何问题。

2 个答案:

答案 0 :(得分:1)

第一个选项:改为使用虚拟功能。

如果每个派生类只有1个且只有1个函数,则效果最佳。

struct A {
    virtual void RunThis(float deltaTime, bool doIt, int32 which) = 0;
    void Tick(float delta, bool doThis )
    {
        //...
        RunThis(delta, doThis, which);
        // ...
    }
    virtual ~A() // virtual destructor...
    {}
};

struct B : public A
{
    virtual void RunThis(float deltaTime, bool doIt, int32 which )
    {
    }
    void DoSomething(/*...*/) 
    {
        // ...
        Tick(/*...*/);
    }

};

第二个选项:std :: function + lambda或struct B中的成员函数

#include <functional>
struct A 
{
     void Tick(float delta, bool doit, std::function<void(float,bool,int32)> action )
     {
     }
};

struct B : public struct A
{
    void DoSomething( /*...*/ )
    {
         // you can use a lambda, if convenient...
         Tick(/*...*/,
             [this](float delta, bool doit, int32_t which) -> void {
                // ...
             });
   }

   // or you can also use a pointer to member:
   void RunThis(/*...*/) { /* ... */ }
   void DoSomething(/*...*/)
   {
        std::function<void(float,bool,int32)> f = std::bind( &B::RunThis, this, _1,_2,_3);
        Tick(/*...*/, f);
   }
 };

答案 1 :(得分:0)

不幸的是,C ++函数指针没有上下文...换言之,指向函数的指针接受整数

void (*f)(int x)

不允许有任何数据&#34;绑定&#34;到指针,只能访问参数和全局变量。 为某些编译器实现的解决方法是"trampoline" libraries,它允许将自定义数据绑定到函数指针,但它们都依赖于在运行时创建动态代码,这在标准C ++的边界内是不可能的。

标准C ++中的解决方案是使用

std::function<void(int)>

而不是

void (*)(int)

std::function对象可以保存与函数关联的数据,并允许创建闭包。它也向后兼容函数指针(即函数指针可以隐式转换为std::function对象)。

使用您的代码可以成为例如

struct A {
    int32 mynum;
    void Tick(float delta, bool doThis,
              std::function<void(float, bool, int32)> funcparam) {
       funcparam(delta, doThis, mynum);
    }
};

struct B : public A {
    void RunThis(float deltaTime, bool doIt, int32 which) {
        // do something when called by Struct A
    };
    void DoSomething() {
        Tick(0.1f, true, [this](float dt, bool di, int32 w) {
            this->RunThis(dt, di, w);
        });
    }
};

其中lambda用于调用方法。

如果无法更改接受函数指针的代码,则可移植的解决方法是为给定的签名设置一组预分配的函数指针...例如

void *closure_data[10];
void (*closure_code[10])(void *, int);

void closure0(int x){ closure_code[0](closure_data[0], x); }
void closure1(int x){ closure_code[1](closure_data[1], x); }
void closure2(int x){ closure_code[2](closure_data[2], x); }
...
void closure9(int x){ closure_code[9](closure_data[9], x); }

void (*closures[10])(int) = {closure0,
                             closure1,
                             ...
                             closure9};

然后你需要&#34;分配&#34;一个闭包i,将您的上下文数据放在相应的closure_data[i]中,代码放在closure_code[i]中,并作为函数指针closures[i]传递。

通常不错的C ++ 03代码或接受回调函数指针的C代码总是提供一个上下文参数...即接口的格式为

void Tick(void *context,
          void (*callback)(float, bool, int32, void *))

并将调用回调函数,同时传递由提供函数指针的调用者指定的不透明void *context