指向成员的指针对托管类无效

A pointer to member is not valid for a managed class

本文关键字:无效 指针 成员      更新时间:2023-10-16

我创建了一个库,其中一个公开的函数接受类型为void(*fun_ptr)(int)的函数指针。

函数语法为:

start_server(char *devices, char *folder, int number, int timeout, void(*status_of_server)(int));

这适用于正常的C++函数,例如void getStatus(int n);但是当我在GUI应用程序的Visual C++环境中使用它们时,我收到此错误:

指向成员的指针对托管类无效

start_server(&devs, &base, 1, 0, &TestApplication::MainWindow::StatusOfServer );

其中StatusOfServer在可用于 UI 管理的MainWindow类中定义。

private: void TestApplication::MainWindow::StatusOfServer(int n)
{
this->progressBar->Value = n;
}

处理这个问题的正确方法是什么?

这种奇怪行为的原因是每个成员函数都隐式地在其签名后附加了一个指向其类型的指针,例如:

#include  <iostream>
struct S
{
int i;
void doSth() { std::cout << i << std::endl; }
};
int main()
{
S s{1};
s.doSth();
auto member_f = &S::doSth;
(s.*member_f)();
}

doSth()有一个隐藏的参数,所以不能像常规函数一样调用它。在您的示例中,情况类似 - 您尝试调用成员函数,就好像它是一个普通的自由函数一样,这将不起作用。通常在请求函数指针的 API 中,函数可以将void*作为参数,这允许您编写一个包装器,将指针强制转换为正确的类型,然后在指向类的实例上调用成员函数。但是,从上面显示的代码来看,您无法将void*传递到函数中,因此您可能具有某种全局状态(例如,使该函数成为静态函数并使其仅对静态数据工作(。

一种解决方案是围绕托管包装器创建一个小型的非托管包装函数:

void wrapStatusOfServer(int n) {
TestApplication::MainWindow::StatusOfServer(n)
}

并获取指向包装器的指针

start_server(&devs, &base, 1, 0, &wrapStatusOfServer);

另一种解决方案:将start_server转换为托管代码,并使用委托而不是函数指针:https://learn.microsoft.com/en-us/cpp/dotnet/how-to-define-and-use-delegates-cpp-cli?view=vs-2017

C++/CLI 充满了此类问题,其中托管和非托管代码和数据几乎但不完全可互操作。