简体   繁体   中英

why i can't call a static member variable in an static member function like this?

everyone! there is a code snippet like the below: 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;
}

when I click "build" button,the output message is

error LNK2001: unresolved external symbol "public: static int Test::b" (?b@Test@@2HA) 1>B:\\PROGRAMPROJECT\\visual 2015 pro\\testcase\\testcase\\x64\\Debug\\testcase.exe : fatal error LNK1120: 1 unresolved externals

but,when i change the code location like this:

  #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;
}

It does work! I don't know why?Anybody can help me? My IDE is vs pro 2015 + windows10.

The other anwers focus on solving the problem, instead of answering the "why" part.

When you define a function within class body, it is automatically considered to be inline and any number of translation units (think about C++ sources) may define them. That's the way you would normally define functions within header file - a function that's body will be include d in multiple sources.

When you only declare a function within class body, but define it outside, it is not automatically marked as inline , which means that each translation unit that contains this definition will generate its own strong symbol. In this case, you usually decouple the declaration in a header file, from implementation in an associated source file, otherwise you'd get multiple symbol errors. (ie if you have non-inline definitions in headers, each source that include them generates those symbols and linker gets confused because it sees multiple versions of the same non-inline function coming from different sources)

Now, when you define a static member variable, unless it's inline, it also must be also associated with a translation unit. It's similar to declaring an extern global variable, that also has to be defined somewhere. In your case, you should simply add:

int Test::b;

It's more important when you decouple definition from declaration. Say, you have two files:

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

The symbols (in this case, the global variable Test::b and the function Test::test ) are associated with the file Test.cpp and are generated exactly once. You may include Test.hpp in any number of source files and no additional symbols will be generated.

For referece, see https://en.cppreference.com/w/cpp/language/static

You've declared Test::b but you haven't defined it. Add this line to your code (outside of the Test class)

int Test::b;

you can give an initial value as well if you wish

int Test::b = 123;

How to solve it

Using C++17 you can inline the static variable which removes the need to define it outside the class.

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

If you cannot use C++17 you will have to define

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

outside of class Test

To the why

When you wrote

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

you defined the function directly in the class (which means it is automatically marked inline). You then also have the definition of your static variable right there. If it is outside of the function scope, it is only a declaration (except if explicitly marked as inline - as shown above).

In contrast, in the other case it is outside of the function definition and hence your are missing the definition of the static variable.

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

Fix spelled out for 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;
    }
};

Fix spelled out prior to 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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM