Unresolved external symbol on static class members
Asked Answered
Q

6

160

Very simply put:

I have a class that consists mostly of static public members, so I can group similar functions together that still have to be called from other classes/functions.

Anyway, I have defined two static unsigned char variables in my class public scope, when I try to modify these values in the same class' constructor, I am getting an "unresolved external symbol" error at compilation.

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

    ...

    test();
};

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

I'm new to C++ so go easy on me. Why can't I do this?

Quintet answered 12/10, 2008 at 7:45 Comment(0)
W
179

If you are using C++ 17 you can just use the inline specifier (see https://mcmap.net/q/152168/-how-to-have-static-data-members-in-a-header-only-library-duplicate)


If using older versions of the C++ standard, you must add the definitions to match your declarations of X and Y

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

somewhere. You might want to also initialize a static member

unsigned char test::X = 4;

and again, you do that in the definition (usually in a CXX file) not in the declaration (which is often in a .H file)

Werth answered 12/10, 2008 at 7:49 Comment(1)
If you are writing header-only library, you can use this technique to avoid cpp file: #11710359Wigley
G
80

Static data members declarations in the class declaration are not definition of them. To define them you should do this in the .CPP file to avoid duplicated symbols.

The only data you can declare and define is integral static constants. (Values of enums can be used as constant values as well)

You might want to rewrite your code as:

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

test::test() {
}

If you want to have ability to modify you static variables (in other words when it is inappropriate to declare them as const), you can separate you code between .H and .CPP in the following way:

.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.
}
Greenhead answered 12/10, 2008 at 7:45 Comment(2)
why here in .CPP, it is "unsigned char test::X = 1;" instead of "test::X = 1;"? static variable X already defined, why still need "unsigned char"? @GreenheadEctophyte
@Ectophyte Because "test::X = 1;" is interpreted as an assignment, whereas what we're trying to do is a definition.Kayekayla
E
9

in my case, I declared one static variable in .h file, like

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

and in myClass.cpp, I tried to use this m_nMyVar. It got LINK error like:

error LNK2001: unresolved external symbol "public: static class... The link error related cpp file looks like:

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

So I add below code on the top of 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
}

then LNK2001 is gone.

Ectophyte answered 18/9, 2018 at 23:35 Comment(0)
C
8

When we declare a static variable in a class, it is shared by all the objects of that class. As static variables are initialized only once they are never initialized by a constructor. Instead, the static variable should be explicitly initialized outside the class only once using the scope resolution operator (::).

In the below example, static variable counter is a member of the class Demo. Note how it is initialized explicitly outside the class with the initial value = 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
Carricarriage answered 17/4, 2021 at 12:59 Comment(1)
literally this solved my issue.Honorine
P
6

Since this is the first SO thread that seemed to come up for me when searching for "unresolved externals with static const members" in general, I'll leave another hint to solve one problem with unresolved externals here:

For me, the thing that I forgot was to mark my class definition __declspec(dllexport), and when called from another class (outside that class's dll's boundaries), I of course got the my unresolved external error.
Still, easy to forget when you're changing an internal helper class to a one accessible from elsewhere, so if you're working in a dynamically linked project, you might as well check that, too.

Prototrophic answered 4/5, 2018 at 7:37 Comment(1)
You also may need __declspec(dllimport) if you initialize the static member in the cpp file.Outfight
P
0

In my case, I was using wrong linking.
It was managed c++ (cli) but with native exporting. I have added to linker -> input -> assembly link resource the dll of the library from which the function is exported. But native c++ linking requires .lib file to "see" implementations in cpp correctly, so for me helped to add the .lib file to linker -> input -> additional dependencies.
[Usually managed code does not use dll export and import, it uses references, but that was unique situation.]

Paulie answered 10/2, 2020 at 13:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.