为什么我不能在这样的静态成员函数中调用静态成员变量?

时间:2018-09-02 09:01:48

标签: c++ static-members static-functions

大家!有一个类似下面的代码片段: testcase.cpp

#include <string>
#include <iostream>
using namespace std;
class Test {
public:
    static int b ;
    static void test()
    {

        b = 3;
         cout << b<<endl;
    }
};
int main()
{
Test::test();

    return 0;
}

当我单击“构建”按钮时,输出消息为

  

错误LNK2001:无法解析的外部符号“ public:static int Test :: b”(?b @ Test @@ 2HA)   1> B:\ PROGRAMPROJECT \ visual 2015 pro \ testcase \ testcase \ x64 \ Debug \ testcase.exe:致命错误LNK1120:1个未解决的外部组件

但是,当我这样更改代码位置时:

  #include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
class Test {
public:
    //static int b;
    static void test()
    {
        static int b;//only change this line
        b = 3;
        cout << b << endl;
    }
};
int main()
{
    Test::test();

    return 0;
}

它确实有效! 我不知道为什么?有人可以帮助我吗? 我的IDE是vs pro 2015 + Windows10。

3 个答案:

答案 0 :(得分:3)

其他答案专注于解决问题,而不是回答“为什么”部分。

当您在类主体中定义一个函数时,它会自动被视为inline,并且任何数量的翻译单元(例如C ++源代码)都可以定义它们。那就是您通常在头文件中定义函数的方式-主体的函数将在多个源中include被保存。

当您仅在类主体中声明一个函数而在外部定义它时,该函数不会自动标记为inline,这意味着每个包含此定义的翻译单元都会生成自己的强符号。在这种情况下,通常会将头文件中的声明与关联的源文件中的实现解耦,否则会出现多个符号错误。 (即,如果标头中包含非内联定义,则每个包含它们的源都会生成这些符号,并且链接器会感到困惑,因为它会看到同一非内联函数的多个版本来自不同的源)

现在,当您定义静态成员变量时,除非它是内联的,否则还必须与翻译单元关联。类似于声明extern全局变量,该变量也必须在某处定义。对于您的情况,您只需添加:

int Test::b;

将定义与声明解耦时,这一点更为重要。假设您有两个文件:

Test.hpp

class Test {
public:
    static int b ;
    static void test();
};

Test.cpp

#include "Test.hpp"
int Test::b;
void Test::test()
{
    b = 3;
    cout << b<<endl;
}

符号(在这种情况下,全局变量Test::b和函数Test::test)与文件Test.cpp相关联,并且仅生成一次。您可以在任意数量的源文件中包含Test.hpp,并且不会生成其他符号。

有关裁判,请参见https://en.cppreference.com/w/cpp/language/static

答案 1 :(得分:2)

您已声明Test::b,但尚未定义。将此行添加到您的代码中(在Test类之外)

int Test::b;

您也可以根据需要提供初始值

int Test::b = 123;

答案 2 :(得分:2)

解决方法

使用C++17可以内联静态变量,从而无需在类外定义它。

static inline int i = 0; // I would also initialize it to zero, just to be sure 

如果您不能使用C++17,则必须定义

int Test::b = 0; // Again I would also initialize it to zero, just to be sure 

Test类之外的

原因

当你写

static void test()
{
    static int b; // <-- definition is here
    b = 3;
    cout << b << endl;
}

您直接在类中定义了函数(这意味着它会自动标记为内联)。然后,您也可以在那里定义静态变量。如果它不在函数范围内,则仅是一个声明(除非明确标记为内联,如上所示)。

相反,在另一种情况下,它在函数定义之外,因此您缺少静态变量的定义。

class Test {
public:
    static int b ; // <-- only declaration - definition is missing
    static void test()
    {
        b = 3;
        cout << b<<endl;
    }
};

针对C ++ 17的修正

class Test {
public:
    static inline int b = 0; // <-- now it is defined (and for safety initialized)
    static void test()
    {
        b = 3;
        cout << b<<endl;
    }
};

修正了C ++ 17之前的问题

#include <string>
#include <iostream>
using namespace std;
class Test {
public:
    static int b;   // declaration
    static void test()
    {
        b = 3;
        cout << b << endl;
    }
};

int Test::b = 0;  // definition

int main()
{
    Test::test();

    return 0;
}