在内联构造函数中访问静态成员时,为什么链接器会失败

时间:2014-11-27 09:51:37

标签: c++ windows dll static linker

刚开始为一个非常简单的自动化测试框架进行编码以供内部使用。 (我知道那里有成百上千的人 - 真的也很好,但此刻并不感兴趣,所以请不要指出我的任何一个,请;))然后我遇到了以下问题我无法解释,因此请求您的帮助。

我将以下代码作为DLL的一部分:

(代码几乎不是一个胚胎,花了我2​​分钟的时间来编写,所以它的逻辑,结构 - 没有 - 在任何方面都得到了改进。)

h文件:

#pragma once

#ifdef __DLL__   // Defined in DLL-project
    #define DLLEXPORT __declspec( dllexport )
#else
    #define DLLEXPORT
#endif

class DLLEXPORT AutoTest
{
public:
            enum    eTestID {TESTID_SomeFunction};
                    AutoTest(eTestID id, LPVOID lpData)
                    {
                        if(sm_bTestsActive)
                            ExecTest(id, lpData);
                    }
            void    ActivateTests();

private:
    static  void    ExecTest(eTestID id, LPVOID lpData)
                    {
                    }
    static  BOOL    sm_bTestsActive;
};

CPP-文件:

#include "StdAfx.h"
#include "AutoTest.hpp"

BOOL AutoTest::sm_bTestsActive = FALSE;

void AutoTest::ActivateTests()
{
    sm_bTestsActive=TRUE;
}

编译得很好,DLL就会生成。

这是我的问题 - 当用以下代码实例化类时

AutoTest(AutoTest::TESTID_SomeFunction, &SomeData);

来自主应用程序,链接器失败并带有

error LNK2001: unresolved external symbol "private: static int AutoTest::sm_bTestsActive" (?sm_bTestsActive@AutoTest@@0HA)

< 2分钟写 - 现在进行5个小时,以了解它失败的原因! :0

这里有什么有趣的 - 如果我将构造函数移动到cpp文件(没有内联)它就可以正常工作了!?!?

以下代码:

h文件:

#pragma once

#ifdef __DLL__   // Defined in DLL-project
    #define DLLEXPORT __declspec( dllexport )
#else
    #define DLLEXPORT
#endif

class DLLEXPORT AutoTest
{
public:
            enum    eTestID {FK3059};
                    AutoTest(eTestID id, LPVOID lpData);
            void    ActivateTests();

private:
    static  void    ExecTest(eTestID id, LPVOID lpData)
                    {
                    }
    static  BOOL    sm_bTestsActive;
};

CPP-文件:

#include "StdAfx.h"
#include "AutoTest.hpp"

BOOL AutoTest::sm_bTestsActive = FALSE;

AutoTest::AutoTest(eTestID id, LPVOID lpData)
{
    if(sm_bTestsActive)
        ExecTest(id, lpData);
}

void AutoTest::ActivateTests()
{
    sm_bTestsActive=TRUE;
}

(我在粘贴后对代码进行了一些小修改,因此可能会有或可能没有简单的语法错误。)

此外,如果我从内联版本构造函数中删除对静态成员的引用,它可以正常工作。

关于内联版本为什么不起作用的任何想法?

2 个答案:

答案 0 :(得分:2)

请注意您对DLLEXPORT的定义。

确保在构建DLL时将其正确扩展为__declspec(dllexport),或在构建客户端时__declspec(dllimport)

我建议使用一个名称比通用DLLEXPORT更具体的宏(以避免与其他具有相同名称的宏冲突)。

从内联成员函数访问静态数据成员对我来说很好(使用VS2013测试)。

最小的重复:

使用空DLL项目和空控制台应用程序项目创建Visual Studio解决方案。

在DLL项目中添加两个文件:

<强> DllClass.h

#pragma once

#ifndef TEST_DLL_CLASS
#define TEST_DLL_CLASS __declspec(dllimport)
#endif

class TEST_DLL_CLASS DllClass
{
public:
    DllClass();

    int GetMember() const
    {
        return m_data1;
    }

    static int GetStaticMember()
    {
        return sm_data2;
    }

private:
    int m_data1;
    static int sm_data2;
};

<强> DllClass.cpp

#define TEST_DLL_CLASS __declspec(dllexport)
#include "DllClass.h"

int DllClass::sm_data2 = 2;

DllClass::DllClass()
    : m_data1(1)
{
}

在控制台应用程序项目中,添加一个文件:

<强> Test.cpp的

#include "..\DllTestClass\DllClass.h"
#include <iostream>
using namespace std;

#pragma comment(lib, "DllTestClass")

int main()
{
    DllClass dllClass;

    cout << dllClass.GetMember() << endl;
    cout << DllClass::GetStaticMember() << endl;
}

确保在构建控制台测试应用程序时,链接器可以找到DLL .lib( DllTestClass.lib )文件。
为此,您可以导航控制台应用程序的项目属性,转到:

Project Properties | Linker | Additional Library Directories

并将$(OutDir)添加到其他库目录中,使其成为:

$(OutDir);%(AdditionalLibraryDirectories)

为我构建并正常工作。

答案 1 :(得分:1)

应该是:

#ifdef __DLL__   // Defined in DLL-project
    #define DLLEXPORT __declspec( dllexport )
#else
    #define DLLEXPORT __declspec( dllimport )
#endif
  

您可以使用dllimportdllexport属性声明C ++类。这些形式意味着导入或导出整个类。以这种方式导出的类称为可导出类。

the documentation中的更多信息。