【问题标题】:Calling a statically-linked static method in C++在 C++ 中调用静态链接的静态方法
【发布时间】:2015-05-24 16:43:26
【问题描述】:

我正在尝试调用 C++ 类的静态链接静态方法,但我收到 VS 链接器错误 LNK2019,“未解析的外部符号”。这是库源代码:

// in header file
#define DllExport __declspec (dllexport)
class MyClass{
public:
    DllExport
    static HWND WINAPI myFunc();
};
// in cpp file
DllExport
HWND WINAPI MyClass::myFunc(){ /* create a GUI window that has instance of MyClass set as its property (using ::SetProp) */ }

myFunc 用作创建 MyClass 对象的入口点,该对象隐藏在库中。只有这样的静态函数才能用于影响 MyClass 实例的功能(通过提供相应的 HWND)。 这是图书馆使用者:

#define DllImport __declspec(dllimport)
DllImport
HWND WINAPI myFunc();
...
int main(){
    HWND hWnd=myFunc();
    ... // work with the window and attached MyClass instance
}

(我相信)所有文件链接都设置正确 - 最初,myFunc 被设计为独立函数并且一切正常。我怀疑一定是某些调用对流不匹配导致链接器在 myFunc 上产生错误。 阅读有关该主题的多篇文章,即

http://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL

https://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx

但他们没有解决我的问题。

感谢您的建议!

【问题讨论】:

  • 您的静态方法是动态链接的。您的导出端很好,因此使用 DLL 的项目是罪魁祸首。确保包含整个类定义和相应的 __declspec(dllimport)。如果您使用 API 宏,该宏在定义预处理器指令(例如:BUILDING_LIB)时配置为导出并导入,则更容易,这样您就可以在两个项目中包含相同的标头。
  • 还要确保链接到存根库,尽管我假设您已经这样做了,因为您无需手动查找符号即可使独立功能正常工作。
  • 好吧,我很确定我是静态链接(生成 LIB 而不是 DLL)。但是令我困惑的是,即使在 MyClass 中除了静态函数之外没有其他公开的函数(我认为静态函数实际上是经典的 C++ 函数),也必须包含整个 MyClass 定义。从我的角度来看,函数的主体“知道”要做什么(无论编译的指令是来自过程代码还是面向对象的代码),所以我现在缺少包含整个类声明的理由。
  • 顺便说一句,刚刚尝试了你的建议,最后 IntelliSense 抱怨“不允许不完整的类型”,指的是我尝试在消费应用程序中调用 MyClass::myFunc()。
  • 哎呀,现在我可以看到混乱了 - 我将此线程命名为“动态链接”。拜托,这个功能真的是静态链接的! (不知道我写的时候在想什么!)

标签: c++ winapi static-methods static-linking


【解决方案1】:

由于您的目标是创建静态库,因此我们要做的第一件事就是消除对dllexport/dllimport 的任何提及。此类说明符仅在您实际创建 DLL 项目时使用。

所以对于lib.h,我们只需要这个(添加了一些包含保护以更好地衡量):

// lib.h
#ifndef LIB_H
#define LIB_H

class MyClass{
public:
    static void myFunc();
};

#endif

WINAPI 规范也是不必要的,因为您是调用该方法的人,并且可以使用默认调用约定而不会出现 ABI 问题(尽管如果您确实想使用 WINAPI,那么您需要包含 @ 987654326@ 在你的头文件中)。

对于lib.cpp,我们只需要这个:

// lib.cpp
#include <Windows.h>
#include "lib.h"

void MyClass::myFunc(){
    ::MessageBox(0,"myFunc call!",NULL,0);
}

对于您的app 项目中的main.cpp,我们只需要这个:

// main.cpp
#include <iostream>
#include <D:\staticlink\lib\lib.h>

int main(){
    std::cout << "ahoj";
    MyClass::myFunc();
    char buf[10];
    std::cin >> buf;
    return 0;
}

我建议配置您的包含路径以通过您的项目设置找到lib.h,而不是在源代码中使用绝对路径,但也许您可以稍后在一切正常后执行此操作。

之后,如果问题仍然存在,您唯一需要确保的是您的 app 项目正确链接到 lib.lib(链接器设置)。

【讨论】:

  • 艾克,谢谢你的正式回答,你快了 9 秒 :-) 即将将其标记为解决我的问题。 :-) 在这方面,非常感谢您为图书馆提供的时间、精力和信息,非常感谢!
  • NP -- 很抱歉编辑您的帖子以指定动态链接。对于将 dllexport 用于静态库,我非常困惑(与链接器一样),所以我认为您的实际目标是创建一个 DLL。有了静态库,就不需要那种东西了。
  • 绝对不是问题 - 会自己更改帖子标题但不知道如何。
  • 值得注意的是,如果您确实想要创建一个 DLL,那么您已经非常接近正确的答案——只需配置 lib 项目以输出一个 DLL。所以如果你下次想要一个 DLL,你应该知道怎么做。
【解决方案2】:

您的导入头文件应该看起来更像:

#define DllApi __declspec (dllexport)
class MyClass{
public:
    DllApi
    static HWND WINAPI myFunc();
};

【讨论】:

  • 包含整个类定义不起作用 - IntelliSense 抱怨“不允许不完整的类型”,指的是我尝试在消费者应用程序中调用 MyClass::myFunc()。 (除非我遗漏了一些观点。)
  • 哎呀,现在我可以看到混乱了 - 我将此线程命名为“动态链接”。拜托,这个功能真的是静态链接的! (不知道我写的时候在想什么!)
猜你喜欢
  • 1970-01-01
  • 2011-07-09
  • 1970-01-01
  • 1970-01-01
  • 2010-09-12
  • 2011-12-09
  • 1970-01-01
  • 2018-03-14
相关资源
最近更新 更多