Here is the .h:
class Logger
{
private:
static int mTresholdSeverity;
public:
static __declspec(dllexport) void log(const char* message);
static __declspec(dllexport) void logFormat(const char* format, ...);
static __declspec(dllexport) int getTresholdSeverity() { return mTresholdSeverity; }
static __declspec(dllexport) void setTresholdSeverity(int tresholdSeverity) { mTresholdSeverity = tresholdSeverity; }
};
And .cpp:
#include "Logger.h"
#include <cstdarg>
int Logger::mTresholdSeverity = 200;
void Logger::log(const char* message)
{
//...
}
void Logger::logFormat(const char* format, ...)
{
//...
}
I get this error:
error LNK2001: unresolved external symbol “private: static int TransformationViewer_Utility_Logging::Logger::mTresholdSeverity” (?mTresholdSeverity@Logger@TransformationViewer_Utility_Logging@@0HA) …
Obviously, mTresholdSeverity is initialized. The error is removed if I comment out getTresholdSeverity() and setTresholdSeverity() or if I move their definition into .cpp file.
Why is there a link error when a static method defined in header file (getTresholdSeverity() or setTresholdSeverity()) uses a static variable (mTresholdSeverity)?
Here is how it works.
Every DLL (or EXE) or otherwise complete “fully-linked” binary, must have definitions of all referenced names, including static variables, including static data members in C++ classes.
They will be separate across DLLs in the application. That means, this variable value will be different, depending on which DLL you look from. Moving the functions to CPP file will make them do a different thing: they will now see the DLL’s copy of the variable and not the EXE’s.
To make what you wrote compile, there has to be the definition from the CPP present in all user binaries at one place. That means, the DLL and the users of the DLL (EXEs or DLLs) must have one CPP file with this definition.
This is a very big hassle, because among other things it makes Singleton pattern impossible (having a shared data object for all users within the program) and each copy of a DLL must have its own static state. Such problem exists only on Windows, with DLLs which are dynamic *loaded * libraries. On UNIX systems, there is a different technology known as Shared Objects (SO). They support true dynamic linking, which means, running the linker to resolve external names at runtime.