【问题标题】:Unresolved external symbol on static class members静态类成员上未解析的外部符号
【发布时间】:2017-10-06 11:19:09
【问题描述】:

简单地说:

我有一个主要由静态公共成员组成的类,因此我可以将仍然必须从其他类/函数调用的类似函数组合在一起。

无论如何,我已经在我的类公共范围内定义了两个静态 unsigned char 变量,当我尝试在同一个类的构造函数中修改这些值时,我在编译时收到“未解析的外部符号”错误。

class test 
{
public:
    static unsigned char X;
    static unsigned char Y;

    ...

    test();
};

test::test() 
{
    X = 1;
    Y = 2;
}

我是 C++ 新手,所以请放轻松。为什么我不能这样做?

【问题讨论】:

    标签: c++ class static members


    【解决方案1】:

    当我们在一个类中声明一个静态变量时,它被该类的所有对象共享。因为静态变量仅在它们从未被构造函数初始化时才被初始化。相反,静态变量应该只在类外部使用范围解析运算符 (::) 显式初始化一次。

    在下面的示例中,静态变量 counter 是 Demo 类的成员。请注意它是如何在初始值 = 0 的类外部显式初始化的。

    #include <iostream>
    #include <string>
    using namespace std;
    class Demo{
       int var;
       static int counter;
    
       public:
       Demo(int var):var(var){
          cout<<"Counter = "<<counter<<endl;
          counter++;
       }
    };
    int Demo::counter = 0;                 //static variable initialisation
    int main()
    {
       Demo d(2), d1(10),d3(1);
    }
    
    Output:
    Count = 0
    Count = 1
    Count = 2
    

    【讨论】:

      【解决方案2】:

      如果您使用的是 C++ 17,您可以只使用 inline 说明符(请参阅 https://stackoverflow.com/a/11711082/55721


      如果使用旧版本的 C++ 标准,则必须添加定义以匹配 X 和 Y 的声明

      unsigned char test::X;
      unsigned char test::Y;
      

      某处。您可能还想初始化一个静态成员

      unsigned char test::X = 4;
      

      再一次,你在定义中(通常在 CXX 文件中)而不是在声明中(通常在 .H 文件中)这样做

      【讨论】:

      【解决方案3】:

      就我而言,我使用了错误的链接。
      它是托管的 c++ (cli),但具有本机导出功能。我已将导出函数的库的 dll 添加到链接器 -> 输入 -> 程序集链接资源中。但是本机 C++ 链接需要 .lib 文件才能正确“查看”cpp 中的实现,所以对我来说,帮助将 .lib 文件添加到链接器 -> 输入 -> 附加依赖项。
      [通常托管代码不使用 dll 导出和导入,它使用引用,但这是一种特殊情况。]

      【讨论】:

        【解决方案4】:

        在我的例子中,我在 .h 文件中声明了一个静态变量,比如

        //myClass.h
        class myClass
        {
        static int m_nMyVar;
        static void myFunc();
        }
        

        在 myClass.cpp 中,我尝试使用这个 m_nMyVar。它得到了 LINK 错误,例如:

        错误 LNK2001:未解析的外部符号“公共:静态类... 链接错误相关的cpp文件如下:

        //myClass.cpp
        void myClass::myFunc()
        {
        myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
        }
        

        所以我在 myClass.cpp 顶部添加以下代码

        //myClass.cpp
        int myClass::m_nMyVar; //it seems redefine m_nMyVar, but it works well
        void myClass::myFunc()
        {
        myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
        }
        

        然后 LNK2001 消失了。

        【讨论】:

          【解决方案5】:

          由于这是我在搜索“具有静态 const 成员的未解决的外部”时似乎出现的第一个 SO 线程,所以我将在此处留下另一个提示来解决未解决的外部问题:

          对我来说,我忘记了标记我的类定义__declspec(dllexport),当从另一个类(在该类的 dll 边界之外)调用时,我当然得到了我未解决的外部错误。
          不过,当您将内部帮助类更改为可从其他地方访问的帮助类时很容易忘记,因此,如果您正在处理动态链接的项目,不妨也检查一下。

          【讨论】:

          • 如果你在cpp文件中初始化静态成员,你可能还需要__declspec(dllimport)
          【解决方案6】:

          类声明中的静态数据成员声明不是它们的定义。 要定义它们,您应该在 .CPP 文件中执行此操作以避免重复符号。

          您可以声明和定义的唯一数据是整型静态常量。 (enums 的值也可以用作常量值)

          您可能希望将代码重写为:

          class test {
          public:
            const static unsigned char X = 1;
            const static unsigned char Y = 2;
            ...
            test();
          };
          
          test::test() {
          }
          

          如果您希望能够修改静态变量(换句话说,当不适合将它们声明为 const 时),您可以通过以下方式将 .H.CPP 之间的代码分开:

          .H :

          class test {
          public:
          
            static unsigned char X;
            static unsigned char Y;
          
            ...
          
            test();
          };
          

          .CPP:

          unsigned char test::X = 1;
          unsigned char test::Y = 2;
          
          test::test()
          {
            // constructor is empty.
            // We don't initialize static data member here, 
            // because static data initialization will happen on every constructor call.
          }
          

          【讨论】:

          • 为什么在 .CPP 中是“unsigned char test::X = 1;”而不是“test::X = 1;”?静态变量 X 已经定义,为什么还需要“unsigned char”? @sergtk
          • @Penny 因为“test::X = 1;”被解释为一个赋值,而我们试图做的是一个定义。
          猜你喜欢
          • 2020-04-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-05-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多