【问题标题】:Error converting void(__cdecl MyClass::*)() to void *将 void(__cdecl MyClass::*)() 转换为 void * 时出错
【发布时间】:2014-12-05 20:37:29
【问题描述】:

我正在尝试链接到我的 QT 应用程序中的外部库。外部库有一个头文件,其中包含我试图调用的以下相关代码:

 extern VGRABDEVICE_API bool V_AssignFrameSizeCallback(IGrabChannel* pChannel, void* pFunc);

在提供的demo C++程序中,编译没有问题,相关代码如下:

// in main.cpp    
void _stdcall MyFrameSizeCallback(T x) {
    do_stuff;
}

int main(int argc, char* argv[]) {
    IGrabChannel* pChannel0 = something;
    V_AssignFrameSizeCallback(pChannel0, MyFrameSizeCallback);
}

我正在尝试将此代码合并到我的 QT 应用程序中,但遇到了问题。在我的 mainwindow.cpp 文件中:

void _stdcall MainWindow::MyFrameSizeCallback(T x) {
    do_stuff;
}

void MainWindow::someFunction() {
    IGrabChannel* pChannel0 = something;
    V_AssignFrameSizeCallback(pChannel0, &MainWindow::MyFrameSizeCallback);
}

我得到的错误是:

error: C2664: 'bool V_AssignFrameSizeCallback(IGrabChannel *,void *)' :
cannot convert argument 2 from 'void (__cdecl MainWindow::* )(T)' to 'void *'
There is no context in which this conversion is possible

我需要做什么?谢谢。

【问题讨论】:

  • 函数指针不是数据指针,不能转换为void*(通常是因为它们更大,尤其是虚拟继承)。这是第三方库 API 中的错误。在任何情况下,您都不能将函数指针从一种调用约定 (__stdcall) 转换为另一种 (__cdecl)。

标签: c++ qt stdcall


【解决方案1】:

你有两个问题。首先,void* 是数据指针,而不是函数指针。根据 C++ 标准,两者之间的转换预计不会起作用。某些平台提供了更强的保证...例如 Windows GetProcAddress 和 *nix dlsym 将两者混合。

接下来,您的&MainWindow::MyFrameSizeCallback 不是函数指针,而是指向成员函数的指针。调用它需要一个 MainWindow 对象,外部库对此一无所知。

您需要向库提供一个普通函数,而不是成员函数。如果您有办法获得MainWindow* 对象指针,那么您可以调用它的成员函数来完成真正的工作。有时库会提供一个“上下文”参数,该参数会传递给您的回调;这是放置对象指针的好地方。否则,您需要将 MainWindow* 存储在全局变量中。如果你只有一个很容易,如果你有多个,你可以选择std::map<IGrabChannel*, MainWindow*>

代码:

MainWindow* MainWindow::the_window;

void MainWindow::MyFrameSizeCallback(T x)
{
    do_stuff;
}

void _stdcall MyFrameSizeCallbackShim(T x)
{
    MainWindow::the_window->MyFrameSizeCallback(x);
}

void MainWindow::someFunction()
{
    IGrabChannel* pChannel0 = something;
    the_window = this;
    V_AssignFrameSizeCallback(pChannel0, &MyFrameSizeCallbackShim);
}

如果参数x 不是IGrabChannel,请相应地更改映射数据类型和插入逻辑。如果参数x 不是某种唯一的可预测标识符,则您可能仅限于对一个MainWindow 实例进行回调。

【讨论】:

  • 很抱歉,但我对 C++ 还是很陌生,仍然很困惑。只有一个 MainWindow 实例,但我不确定如何将 MainWindow* 存储为全局变量。此外,实际输入要多得多:void MainWindow::MyFrameSizeCallback(int a, int b, float c,...),但都是唯一且可预测的。
  • @user2406671:我更新(简化)了一个窗口的代码。我使用了静态成员,但您也可以使用真正的全局成员(从 the_window 前面取出 MainWindow::
  • 我想我们快到了。现在我的错误是:mainwindow.obj:-1: error: LNK2001: unresolved external symbol "public: static class MainWindow * MainWindow::the_window" (?the_window@MainWindow@@2PEAV1@EA) 我需要在哪里定义MainWindow* MainWindow::the_window?有对应的mainwindow.h文件
  • 除非您在我的回答中遗漏了第一行代码,否则您不会收到该错误。将它放在任何实现文件中,可能与使用它的函数一起。不要将定义放在标题中,因为这会导致多个定义错误。
  • 非常感谢。我现在已经让它工作了。我想出了如何访问当前的 MainWindow 对象,现在一切正常。 MainWindow *mw=(MainWindow*)qApp->topLevelWidgets().at(0);
猜你喜欢
  • 2018-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-24
  • 1970-01-01
  • 1970-01-01
  • 2021-10-16
相关资源
最近更新 更多