我有两个结构,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::
并没有解决任何问题。
答案 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
。