我需要解决一个在C++中棘手的问题。有一个dll,我不能修改它。它接受一个函数指针作为参数。如果我传递一个指向全局函数的指针,一切都正常。不幸的是,有一组相同类对象需要传递给dll。在C#中,我通过使用委托解决了这个问题。在C++中该如何实现?使用std::function并不起作用。使用它会导致运行时出现编码约定错误。最好使用MSVC2010。
#include <stdio.h>
// global function which works
void __stdcall task_global(float x, float y) { printf("Called global function with: %f %f\n", x, y); }
typedef void(__stdcall *f_pointer)(float, float);
// try of using a member function
class BaseTask {
public:
virtual void __stdcall task(float x, float y) = 0;
};
class ListeningTask :public BaseTask {
public:
void __stdcall task(float x, float y) { printf("Called this member function with: %f %f\n", x, y); }
};
typedef void (BaseTask::*member_f_pointer)(float, float);
// the dll to use
class RegisterTask {
public:
// no posibility to access or modify!
void __stdcall subscribe(f_pointer fp) { fp(1.0f, 2.0f); }
// just for demonstration how to use a member function pointer
void __stdcall subscribeMemberDemo(member_f_pointer mfp) { /*how to use mfp?*/};
};
int main() {
RegisterTask register_task{};
// use global function
f_pointer pointer_to_global_task = task_global;
register_task.subscribe(pointer_to_global_task);
/*---------------------------------------------------------------*/
// use member function?
std::list<ListeningTask> listening_task_list;
for(int i = 0; i < 10; i++) {
listening_task_list.push_back(ListeningTask lt);
member_f_pointer pointer_to_member_task = &listening_task_list.back().task; //error C2276: '&': illegal operation on bound member function expression
register_task.subscribeMemberDemo(pointer_to_member_task);
// the tricky and important one to solve
// how to pass the member function to this subscribe(f_pointer)?
register_task.subscribe(pointer_to_member_task);
}
getchar();
return 0;
}
重要的问题是如何将成员函数指针传递给
RegisterTask::subscribe(f_pointer)
?括号内的问题是如何将成员函数传递给
RegisterTask::subscribeMemberDemo(member_f_pointer)
?我希望有人可以帮助我解决这个问题,我已经工作了好几天了。
编辑:我修改了问题以强调
ListenerTask
列表的问题。如何传递成员函数指针现在已经通过@pokey909和@AndyG的回答变得清晰明了。他们都提供一个对象或一组对象的指针。如果调用回调,则会同时调用一个ListenerTask
或所有std::list<*ListenerTask>
。但如何让列表中的仅一个ListenerTask
被调用呢?传递多个回调到dll似乎可行。因为以下使用全局函数的示例可以正常工作。void __stdcall task_global_1(float x, float y) { printf("Called global function 1 with: %f %f\n", x, y); }
void __stdcall task_global_2(float x, float y) { printf("Called global function 2 with: %f %f\n", x, y); }
void __stdcall task_global_3(float x, float y) { printf("Called global function 3 with: %f %f\n", x, y); }
typedef void(__stdcall *f_pointer)(float, float);
int main() {
// give the functions to the dll.
f_pointer pointer_to_global_task_1 = task_global_1;
register_task.subscribe(pointer_to_global_task_1);
f_pointer pointer_to_global_task_2 = task_global_2;
register_task.subscribe(pointer_to_global_task_2);
f_pointer pointer_to_global_task_3 = task_global_3;
register_task.subscribe(pointer_to_global_task_3);
}
有三个全局函数指针。它们都被提供给dll。现在,如果dll有一个task_global_2
任务,它只会通知这个!如何通过成员函数指针实现这种区分?
注意: 我得到了dll的源代码。希望这可以帮助解决问题。不幸的是,修改和构建是不可能的。这里是回调定义:
type TCallback = procedure( x : single; y : single; ); stdcall;
procedure subscribe(aCallback: TCallback ); StdCall;
begin
TaskSocket.addTask( aCallback );
end;
procedure TSocket.addTask( aCallback : TCallback);
var newTask : TTask;
begin
newTask := TTask.Create(aCallback);
TaskList.addItem(newTask);
end;
this
参数会让你无从下手。相反,将调用你想要执行的方法的静态方法传递到 dll 中。你需要找到一些方法来知道在静态方法中调用哪个对象。如果你只有一个对象实例,那么这将很容易。如果不是... - user4581301RegisterTask::subscribe
没有声明为静态的?它并没有使用this
。 - Barmarfloat
类型参数。因此,没有void *
参数可以保存对象的指针。 - Barmarpublic delegate void TaskDelegate(float x, float y);
这样的委托来指向对象。 - solarisx