静态类成员上未解析的外部符号

简单地说:

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

无论如何,我已经在类的公共作用域中定义了两个静态无符号字符变量,当我试图在同一个类的构造函数中修改这些值时,在编译时会得到一个“未解析的外部符号”错误。

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


...


test();
};


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

我是 C + + 的新手,所以对我好一点。为什么我不能这样做呢?

158010 次浏览

如果您正在使用 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 档案)

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

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

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

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


test::test() {
}

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

:

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.
}

由于这是我在搜索“带有静态常量成员的未解决外部项”时遇到的第一个 SO 线程,因此我将在这里留下另一个提示来解决一个带有未解决外部项的问题:

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

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

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

在 myClass.cpp 中,我尝试使用这个 m _ nMyVar:

错误 LNK2001: 未解析的外部符号“ public: static class..。 与链接错误相关的 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就不见了。

在我的例子中,我使用了错误的链接。
它由 c + + (cli)管理,但是使用本机导出。我已经将函数从其中导出的库的 dll 添加到 linker-> input-> Assembly link 资源中。但是本地 c + + 链接需要。Lib 文件来正确地“查看”cpp 中的实现,所以对我来说有助于添加。Lib 文件到 linker-> input-> 其他依赖项。
[通常托管代码不使用 dll 导出和导入,它使用引用,但这是唯一的情况。]

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

在下面的示例中,静态变量计数器是类 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