不同库中具有相同文件名的类继承问题

Classes with same file name in different libs inheritance issue

提问人:Tim Handschack 提问时间:2/3/2012 更新时间:2/7/2012 访问量:1570

问:

当从位于不同库中的具有相同文件名的类继承时,链接器会产生未解决的外部符号错误。想想这个继承: LIB2::MyClass : public LIB1::MyClass。

静态库“lib1”:

MyClass.h:

namespace LIB1
{

    class MyClass
    {
    public:
        MyClass();

        ~MyClass();
    };
}

静态库“lib2”:

MyClass.h:

    #include "..\MyClass.h"  // Header of MyClass from lib1 somewhere else than this header file
    namespace LIB2
    {

        class MyClass : public LIB1::MyClass
        {
        public:
            MyClass();

            ~MyClass();
        };
    }

假设两个 .cpp 文件都存在。

lib1 中的 lib2 链接

然后,一些可执行文件尝试在 lib2 中链接并使用派生的 MyClass,例如

#include "\lib2\MyClass.h"

int main()
{
    LIB2::MyClass c;            
}

链接失败,并显示

错误 LNK2001:未解析的外部符号“public: __thiscall LIB1::MyClass::~MyClass(void)

(CTOR相同)

当我简单地将其中一个MyClass.cpp的文件名更改为MyClass1.cpp时,一切都很好。

我怀疑链接器不是在 lib1.lib 中搜索 LIB1:MyClass 的定义,而是尝试在 MyClass.obj(来自 lib2)中找到它们。

这种行为感觉太奇怪了,不可能是故意的。我错过了什么?

此外,当在 VS2005/2010 中设置解决方案时,包括库和可执行文件,并让 VS 通过项目属性->通用属性->框架和引用设置所有库依赖项(而不是在链接器设置中提供库的路径),链接成功。

C++ 继承静态 未解析外部

评论

0赞 Tim Handschack 2/3/2012
编辑:链接器不是在 lib1.lib 中搜索 LIB1:MyClass 的定义,而是尝试在 MyClass.obj(来自 lib2)中找到它们,我怀疑......对不起,忘了,这没有任何意义

答:

0赞 chess007 2/6/2012 #1

我刚刚在 Microsoft Visual C++ Express 中制作了一个解决方案,其中包含两个静态库项目(lib1 和 lib2)和一个应用程序项目(main),其中包含您描述的内容,并且能够重现您的问题。这是我得到的完整构建输出:

1>------ Build started: Project: lib1, Configuration: Debug Win32 ------
1>  MyClass.cpp
1>  lib1.vcxproj -> c:\users\samuel windwer\documents\visual studio 2010\Projects\linker_test\Debug\lib1.lib
2>------ Build started: Project: lib2, Configuration: Debug Win32 ------
2>  MyClass.cpp
2>  Replacing Debug\MyClass.obj
2>  lib2.vcxproj -> c:\users\samuel windwer\documents\visual studio 2010\Projects\linker_test\Debug\lib2.lib
3>------ Build started: Project: main, Configuration: Debug Win32 ------
3>  main.cpp
3>lib2.lib(MyClass.obj) : error LNK2019: unresolved external symbol "public: __thiscall LIB1::MyClass::MyClass(void)" (??0MyClass@LIB1@@QAE@XZ) referenced in function "public: __thiscall LIB2::MyClass::MyClass(void)" (??0MyClass@LIB2@@QAE@XZ)
3>lib2.lib(MyClass.obj) : error LNK2019: unresolved external symbol "public: __thiscall LIB1::MyClass::~MyClass(void)" (??1MyClass@LIB1@@QAE@XZ) referenced in function "public: __thiscall LIB2::MyClass::~MyClass(void)" (??1MyClass@LIB2@@QAE@XZ)
3>c:\users\samuel windwer\documents\visual studio 2010\Projects\linker_test\Debug\main.exe : fatal error LNK1120: 2 unresolved externals
========== Build: 2 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

消息“Replacing Debug\MyClass.obj”阐明了该问题。此消息是由 Microsoft 的库管理器 (LIB.EXE) 在构建 lib2.lib 时发出的。为了理解此消息,重要的是要准确了解静态库文件 (.lib) 是什么,以及 LIB.EXE 的确切功能。

首先要做的是:在构建静态库时,实际上没有链接任何代码。.lib 文件只是一个存档,其中包含一个或多个 .obj 文件。换句话说,.lib 文件的目的是提供一种方便的方式,将 .obj 文件的集合分发为一个文件。LIB.EXE所做的只是将项目的.obj文件打包成一个.lib文件。LIB.EXE 还具有对 .lib 文件执行其他操作的选项,例如列出所有包含的 .obj 文件并提取它们;有关详细信息,请参阅 MSDN

您的问题指出“lib1 中的 lib2 链接”。我假设这意味着您将 lib1.lib 作为 lib2 项目设置中的“附加依赖项”,如下图所示:

enter image description here

为了准确理解将 .lib 文件添加为静态库项目的“附加依赖项”有什么作用,在更改此设置后,我按照此答案中的过程查看运行 LIB.EXE 构建 lib2.lib 时使用的命令行。这里是:

lib.exe "/OUT:c:\users\samuel windwer\documents\visual studio 2010\Projects\linker_test\Debug\lib2.lib" lib1.lib /LIBPATH:..\Debug Debug\MyClass.obj

此命令生成一个名为 lib2.lib 的新静态库文件,其中包含 lib1.lib 中的所有 .obj 文件以及 MyClass.obj。lib1.lib 还包含一个名为 MyClass.obj 的对象这一事实是问题的根源。如 LIB 中所述。EXE在MSDN上的文档

若要将库成员替换为新对象,请指定包含要替换的成员对象的库以及新对象(或包含该对象的库)的文件名。当多个输入文件中存在同名对象时,LIB 会将 LIB 命令中指定的最后一个对象放入输出库中。

当 LIB.EXE 看到 MyClass.obj 的第二个实例时,消息“正在替换 Debug\MyClass.obj”将打印到控制台,因为它认为第二个 MyClass.obj 应该替换第一个实例。将其中一个 MyClass.cpp 文件重命名为 MyClass1.cpp 可解决此问题,因为不再有两个名为 MyClass.obj 的对象文件,因此它们可以在同一个 .lib 文件中愉快地共存。

似乎您已经为此提出了一些解决方法,但希望您现在了解您所看到的行为。

评论

0赞 Tim Handschack 2/6/2012
感谢您阐明链接。禁用 LIB.exe 的 /NOLOGO 选项后,我可以看到打包到库中的对象文件由它们的相对路径引用。对于 MyClass 示例,命令行输出如下所示: Debug/MyClass.obj 替换为 Debug/MyClass.obj 因此,整个问题的解决方案是简单地将 lib1 的目标文件保存到与 lib2 的目标文件不同的位置。(DebugLib1/*.obj、DebugLib2/*.obj)然后,lib1 的对象可以链接到 lib2 中,而不会在具有相同文件名的情况下冲突对象名称。
0赞 chess007 2/7/2012
不客气。我很高兴我的回答帮助您想出了一个更理想的解决方案来解决您的问题。