关于c ++:静态类成员上未解析的外部符号

Unresolved external symbol on static class members

非常简单地说:

我有一个主要由静态公共成员组成的类,所以我可以将类似的函数分组在一起,这些函数仍然需要从其他类/函数调用。

总之,我在类公共范围中定义了两个静态无符号char变量,当我试图在同一类的构造函数中修改这些值时,编译时会出现"未解析的外部符号"错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class test
{
public:
    static unsigned char X;
    static unsigned char Y;

    ...

    test();
};

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

我对C++很陌生,所以对我要宽容些。为什么我不能这么做?


您忘记添加定义来匹配您的x和y声明

1
2
unsigned char test::X;
unsigned char test::Y;

某处。您可能还需要初始化静态成员

1
unsigned char test::X = 4;

同样,您在定义中(通常在CXX文件中)而不是在声明中(通常在.h文件中)这样做。


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

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

您可能需要将代码重写为:

1
2
3
4
5
6
7
8
9
10
class test {
public:
  const static unsigned char X = 1;
  const static unsigned char Y = 2;
  ...
  test();
};

test::test() {
}

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

h:

1
2
3
4
5
6
7
8
9
10
class test {
public:

  static unsigned char X;
  static unsigned char Y;

  ...

  test();
};

CPP:

1
2
3
4
5
6
7
8
9
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.
}


由于这是搜索"具有静态常量成员的未解析外部对象"时出现的第一个so线程,因此我将在此处留下另一个提示来解决具有未解析外部对象的问题:

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


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

1
2
3
4
5
6
//myClass.h
class myClass
{
static int m_nMyVar;
static void myFunc();
}

在myclass.cpp中,我尝试使用这个m_nmyvar。它有如下链接错误:

错误LNK2001:无法解析的外部符号"public:静态类…链接错误相关的cpp文件如下:

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

所以我在myclass.cpp的顶部添加了下面的代码

1
2
3
4
5
6
//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就不见了。