Using static members across Static Lib and DLL - member value is resetting - c++

I have a solution set up with 3 projects:
Lib1 (A static library)
Dll1 (A dynamic library)
App1 (A Blank Windows Store application, could be any application type)
Lib1 contains the following:
Export.h
#pragma once
#ifdef DLL_EXPORT
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
Lib1.h
#pragma once
#include "Export.h"
class Member { };
class EXPORT Base {
public:
static Member* GetStaticMember();
virtual void SetMember(Member* member) = 0;
protected:
static Member* m_member;
};
class Worker {
public:
void DoSomething();
};
Lib1.cpp
#include "pch.h"
#include "Lib1.h"
Member* Base::m_member;
Member* Base::GetStaticMember() {
return m_member;
}
void Worker::DoSomething() {
Member* test = Base::GetStaticMember(); // RETURNS 0
}
Dll1 contains the following
Dll1.h
#pragma once
#include "Lib1.h"
#include "Export.h"
class EXPORT ChildA : public Base {
public:
virtual void SetMember(Member* member) override;
};
Dll1.cpp
#include "pch.h"
#include "Dll1.h"
void ChildA::SetMember(Member* member) {
Base::m_member = member;
Member* test = Base::GetStaticMember(); // RETURNS CORRECT ADDRESS
}
App1 contains the following
Member* member = new Member();
ChildA* childa = new ChildA();
childa->SetMember(member); // Base::GetStaticMember() inside this RETURNS CORRECT ADDRESS
Worker* worker = new Worker();
worker->DoSomething(); // Base::GetStaticMember() inside this RETURNS 0
The Problem
When stepping through in the debugger, Base::GetStaticMember() returns the correct address to the member after it is set (but still while inside childa->SetMember(). Once OUTSIDE childa, Base::GetStaticMember() returns 0 instead. When inside worker->DoSomething(), Base::GetStaticMember() is also returning 0. Can anyone explain to me what the cause of this is and how to fix it so that accessing Base::GetStaticMember() either outside or inside methods of the Dll or Lib will return the correct address and not 0?

If you're using a static lib linked to multiple DLL's and/or your EXE, each will get its own static member variable. Think of the mechanics of how the *link phase of each of these happens and you'll see why.
You can turn your static vars into pointers referencing shared memory backed by a memory mapped file, but I warn you it gets tricky to manage. I've done it by maintaining a temp memory-map-file using the name of the class+member+pid as the mapping name (note: the pid was to allow multiple processes to run without stomping on each others shared mem). it worked surprisingly well.

You should link lib1 only with Dll1 or with App1, not both.
Now you have Base::_member defined both in your Dll1 and App1.
As you defined your Base class __dllexport/__dllimport, it uses Dll1 static member, but you din't declared Worker with any attributes, and it uses local static member.
I assume, you should specify attributes for Worker and do not link App1 with Lib1

Related

Static member used as default parameter leads to unresolved externals

I have a confusing issue using a static member variable as a default parameter. Since the same language construct works in a different place, it might be related to project (DLL) inter-dependencies. So please accept my apologies if my example is too complex, but I should draw the whole picture since I do not have any idea what is wrong.
I have a base class (representing kind of an error code)
ErrorBase.h
class ErrorBase
{
public:
typedef unsigned long ErrorCode;
/// here go the error codes. For reasons I do not want to explain, I cannot use an enumeration here.
static const ErrorCode ERROR_UNINITIALIZED;
static const ErrorCode ERROR_OK;
///...and so on
ErrorBase(ErrorCode theCode = ERROR_UNINITIALIZED);
};
...and in ErrorBase.cpp, I am assigning values to the codes...
const ErrorBase::ErrorCode ErrorBase::ERROR_UNINITIALIZED = 0xffffffff;
const ErrorBase::ErrorCode ErrorBase::ERROR_OK = 0x0;
//.. and so on...
ErrorBase is exported from a DLL which provides some general purpose classes to our project
Now I am deriving another error class for more specific errors which has additional attributes specific for the particular type of error. The class SpecificError is part of a different DLL which links to the general purpose DLL containing ErrorBase. I have not included the dllimport/dllexport shebang, but we are using this all over the place and it works in all cases. If you have doubts, I can edit my code example.
SpecificError.h
class SpecificError : public ErrorBase
{
public:
static const ErrorCode SPECIFIC_ERROR_UNINITIALIZED;
static const ErrorCode SPECIFIC_ERROR_SOMETHING_WENT_WRONG;
SpecificError(ErrorCode theCode = SPECIFIC_ERROR_UNINITIALIZED);
};
... and in the SpecificError.cpp I am defining these values:
const SpecificError::ErrorCode SpecificError::SPECIFIC_ERROR_UNINITIALIZED = ErrorBase::ERROR_UNINITIALIZED;
Like ErrorBase, SpecificError is exported from the DLL handling specific functionality. Note that both error classes declare a constructor using the "UNINITIALIZED" value as a default for the error code.
Now I have a program being dependent on both DLLs, thus linking to both of them through the corresponding import libraries. This program includes ErrorBase.h and SpecificError.h. It does not seem to have any problems with ErrorCode.h, but about SpecificError.h I am receiving an
LNK2001 unresolved external symbol SpecificError::ErrorCode SpecificError::SPECIFIC_ERROR_UNINITIALIZED referenced in main.obj.
(remark: main.cpp does not explicitly use SpecificError, it just includes the header file).
I was able to work-around the problem by removing the default parameter from the SpecificError constructor and declaring a default constructor which in its implementation calls the inherited constructor of ErrorBase passing SPECIFIC_ERROR_UNINITIALIZED to it. This leads me to the assumption that the symbol SPECIFIC_ERROR_UNINITIALIZED is properly declared and defined but cannot be used as a parameter default. However, this seems to apply to SpecificError only, everything seems fine in ErrorBase.
Toolset: I am using Visual C++ 2017 as a compiler.
I recreated the linked error. Make the following changes to your files and it should work just fine based on the code snippets that you showed above:
SpecificError.cpp
// I sent theCode to the Base class
SpecificError::SpecificError(ErrorCode theCode) : ErrorBase(theCode)
{
// ...
}
In ErrorBase.cpp I just added the constructor but you probably already have this:
ErrorBase::ErrorBase(ErrorCode theCode)
{
// ...
}
After I did this, I had to also move the initializations of the static consts to the .h from the .cpp files. Then I tested the code by doing:
SpecificError e; // theCode ends up being 0xffffffff
SpecificError e1(20); // theCode ends up being 20
I hope that this helps you.
Here is what my ErrorBase.cpp looks like:
#pragma once
#include"ErrorBase.h"
#include<iostream>
ErrorBase::ErrorBase(ErrorCode theCode) {
std::cout << theCode << std::endl;
}
ErrorBase.h:
#pragma once
class ErrorBase
{
public:
typedef unsigned long ErrorCode;
static const ErrorCode ERROR_UNINITIALIZED = 0xffffffff;
static const ErrorCode ERROR_OK = 0x0;
ErrorBase(const ErrorCode = ERROR_UNINITIALIZED);
};
SpecificError.cpp:
#pragma once
#include"SpecificError.h"
SpecificError::SpecificError(ErrorCode theCode) : ErrorBase(theCode)
{
}
SpecificError.h:
#pragma once
#include "ErrorBase.h"
class SpecificError : public ErrorBase
{
public:
static const ErrorCode SPECIFIC_ERROR_UNINITIALIZED = ErrorBase::ERROR_UNINITIALIZED;
static const ErrorCode SPECIFIC_ERROR_SOMETHING_WENT_WRONG = -42;
SpecificError(ErrorCode theCode = SPECIFIC_ERROR_UNINITIALIZED);
};
I tried this and it is working, the class name was missing in ErrorBase.cpp
const ErrorBase::ErrorCode ErrorBase::ERROR_UNINITIALIZED = 0xffffffff;
const ErrorBase::ErrorCode ErrorBase::ERROR_OK = 0x0;
If still not working then let me know.
You doing it wrong. The linker error means that it doesn't know where to get your constant value. You should use dynamic linkage with a first DLL. Let me show
Example of C++ class export:
C++ How to export a static class member from a dll?
And your code should be changed:
ErrorBase.h
#ifndef MAIN_DLL
#define MAIN_DLL 1 // or you can add MAIN_DLL definition to the your first project Macroses
#endif
#if MAIN_DLL
#define ERROR_API __declspec(dllexport) // export things to other modules
#else
#define ERROR_API __declspec(dllimport) // import things from the external DLL
#endif
class ERROR_API ErrorBase
{
public:
typedef unsigned long ErrorCode;
/// here go the error codes. For reasons I do not want to explain, I cannot use an enumeration here.
static const ErrorCode ERROR_UNINITIALIZED;
static const ErrorCode ERROR_OK;
///...and so on
ErrorBase(ErrorCode theCode = ERROR_UNINITIALIZED);
};
SpecificError.h
#pragma once
#define MAIN_DLL 0
#include "../Dll_stack_ovfl1/ErrorBase.h" // change it to your path
class SpecificError : public ErrorBase
{
public:
static const ErrorCode SPECIFIC_ERROR_UNINITIALIZED;
static const ErrorCode SPECIFIC_ERROR_SOMETHING_WENT_WRONG;
SpecificError(ErrorCode theCode = SPECIFIC_ERROR_UNINITIALIZED);
};
And the final step, configure the second DLL project to link it with exports of the first one:
Configuration Properties/Linker/Input/Additional dependencies
Add something like "$(SolutionDir)$(Configuration)\ErrorBase.lib"
Once again its just example, I don't know the real path of "lib" file and your project name for ErrorBase DLL - change it to your specific.

C++ nullptr member objects cause "Unable To Read Memory" in DLL Shared Library

I'm crating a DLL in C++ which handles different classes: in particular I have a main class which have a lot of member objects of the other the classes. For exmaple I have my class "A" which has a member of class "B":
Class A header
#include "BClass.h"
class __declspec(dllexport) A
{
B* objectB = nullptr;
public:
A();
initClassB();
}
Class A cpp:
A::A() { // Class A constructor. In these statements B is still nullptr}
A::initCLassB() { objectB = new B() }
Class B header:
class __declspec(dllexport) B
{
int x;
bool y;
char* z;
public:
B() { // class B constructor}
}
When I import my DLL in my target project, it compiles with no error, and until here everything's ok.
My main is something like:
#include "AClass.h"
int main()
{
A a;
return 0;
}
Notice that I don't invoke initClassB() in my main and this cause the error "Unable To Read Memory". If I explore the debugger I see that the error is related to all A::objectB members.
Why is this happening? Can't the shared library handle a nullptr member object?
I'm quite new in compiling DLL and this error looks a bit weird to me
DLLs on windows need to export their symbols when building the dll. Client code that uses the library needs to import it.
In your header for class B:
class __declspec(dllexport) B
This is what you want when building the library, but in code that uses it, you want it to be dllimport instead. Usually people use macros to toggle this, with it defaulting to import, and only exporting if a special commandline macro is set.
See this Macro for dllexport/dllimport switch

C++03 linker "already defined symbol" doesn't appear on intermediate file

I am having a problem with a large project on visual studio 2005 on which I have run out of ideas.
I can't even put a working code snippet because I don't know what's related, but I will try:
I needed to make each .cpp file in my project have its own ID number, and create an instance of an object (which is globally accessible) that knows that ID.
I followed the help on the accepted answer on this thread How to manage file unique IDs in c++
and made it work in a sandbox environment.
Adding files, giving them a unique #define FILEID (FileId::ID_FileName)
and then accessing their instance works fine on the sandbox.
Now comes the trouble -
I pasted the code that makes files know their IDS to the main project, and compiled.
So far so good.
Now, I added to one of the existing .cpp files in the project:
#include "ids.h"
#define FILEID File1 // The FileId corresponding to this file
#include "global.h"
Still compiles, links, all good.
Adding these lines to a (any) second .cpp file in the project
now gives link error:
in which:
name1: 1st file I added the lines to (alphabeticcaly)
name2: other unrelated filename (which can also be the 2nd file I added the lines to, but may as well be just some other file)
The error
in name2.obj : error LNK2005: "public static class Instance & __cdecl Manager<3>::getInstance(void)" (?getInstance#$Manager#$02##SAAAVInstance##XZ) already defined in name1.obj
Some times the error is only in the second file, and sometimes (between consecutive builds without changes) the error appears on every .cpp file in the folder.
Looking in the intermediate file (the preprocessor output) on the files to which I added the lines shows exactly one appearance of the
template <>
Instance &Manager<FILEID>::getInstance()
{
static Instance theInstance = getTheFactory().getInstance(FILEID);
return theInstance;
};
with the correct FileId::ID_FileName, which is a different name than that of the other file.
Still, the linker thinks the same FileId is used in more than one file.
On unrelated files (which also give the exact same error), there is no appearance of getInstance() at all. Apparently, there shouldn't be a reason for the linker to shout there.
I checked, and no .cpp files include each other somewhere in the project.
I am completely out of ideas as to what could cause this
and would appreciate any help.
EDIT 1
ids.h
enum FileId{
ID_file1ID=3,//just to see a non zero number in the debugger, which I do
ID_file2ID,
//and so on
FileIdSize
}
EDIT 2
When these errors start, the compiler starts to behave extremely unexpectedly.
Adding the line sdfsdfgasaedfahjk to any file STILL COMPILES AND PASSES.
it clearly states the file name to which the line has been added to compiles.
It clearly states it links to it.
It passes.
I now can't trust the compiler.
No idea what's going on.
You have 2 cpp files defining the FILEID to the same value 3.
As for a MCVE:
ids.h:
#pragma once
#define File1 3
#define File2 3 //<--same value on purpose
global.h
struct Instance
{
};
struct Factory
{
Instance getInstance(int FileID) { return Instance(); }
};
template <int ID>
struct Manager
{
Factory factory;
Instance& getInstance();
Factory& getTheFactory() { return factory; }
};
template <>
Instance& Manager<FILEID>::getInstance()
{
static Instance theInstance = getTheFactory().getInstance(FILEID);
return theInstance;
};
name1.cpp
#include "ids.h"
#define FILEID File1 // The FileId corresponding to this file
#include "global.h"
name2.cpp
#include "ids.h"
#define FILEID File2 // The FileId corresponding to this file
#include "global.h"
As this compiles there is a special implementation for Manager<3>::getInstance(void) created for both name1.cpp and name2.cpp.
You can't use the same value for FILEID in 2 different compilation units.
EDIT: Check values while compiling
Requires the preprocessor definition __BASE_FILE__="%(Filename)%(Extension)"
(Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions)
template <>
Instance& Manager<FILEID>::getInstance()
{
#define _STR(x) #x
#define STR(x) _STR(x)
#define CHECK_ID() __pragma(message("Initializing \"Instance& Manager<FILEID>::getInstance()\" with FILEID="STR(FILEID)" in "STR(__BASE_FILE__)))
CHECK_ID()
static Instance theInstance = getTheFactory().getInstance(FILEID);
return theInstance;
};
Example-Output:
1>------Build started : Project : Test_Call, Configuration : Debug Win32------
1> name1.cpp
1> Initializing "Instance& Manager<FILEID>::getInstance()" with FILEID = FileId::ID_file1ID in "name1.cpp"
1> name2.cpp
1> Initializing "Instance& Manager<FILEID>::getInstance()" with FILEID = FileId::ID_file2ID in "name2.cpp"
1> Test_Call.vcxproj-><Project>\Debug\Test_Call.exe
== == == == == Build: 1 succeeded, 0 failed, 0 up - to - date, 0 skipped == == == == ==
EDIT: Using FileId values as template parameter (MSVE)
id.h
#pragma once
enum FileId {
ID_file1ID = 3,//just to see a non zero number in the debugger, which I do
ID_file2ID,
//and so on
FileIdSize
};
global.h
#pragma once
#include "ids.h"
struct Instance
{
};
struct Factory
{
Instance getInstance(int FileID) { return Instance(); }
};
template <FileId ID>
struct Manager
{
static const FileId manager_id = ID;
static Factory& getTheFactory() { return m_factory; }
static Instance& getInstance()
{
static Instance theInstance = getTheFactory().getInstance(manager_id);
return theInstance;
}
private:
static Factory m_factory;
};
global.cpp
#include "global.h"
Factory Manager<FileId::ID_file1ID>::m_factory;
Factory Manager<FileId::ID_file2ID>::m_factory;
name1.cpp
#include "global.h"
void test1()
{
Instance& a = Manager<FileId::ID_file1ID>::getInstance();
}
name2.cpp
#include "global.h"
void test2()
{
Instance& a = Manager<FileId::ID_file2ID>::getInstance();
}
test.cpp
#include <iostream>
#include "global.h"
using namespace std;
int main(int argc, char** argv)
{
Instance& a = Manager<FileId::ID_file1ID>::getInstance();
Instance& b = Manager<FileId::ID_file2ID>::getInstance();
Instance& c = Manager<FileId::ID_file1ID>::getInstance();
Instance* aptr = &a;
Instance* bptr = &b;
Instance* cptr = &c;
printf("aptr==bptr -> %s\n", (aptr == bptr) ? "true" : "false"); //->false
printf("aptr==cptr -> %s\n", (aptr == cptr) ? "true" : "false"); //->true (both use the instance from ID_file1ID
printf("bptr==cptr -> %s\n", (bptr == cptr) ? "true" : "false"); //->false
}
This is not an answer, but may prove useful in finding out what is wrong.
The following code is essentially the same as the original answer, but with all complexity stripped away at the expensive of needing boilerplate code in various places.
idmanager.h
struct Instance {/*...*/};
Instance &getFile1Instance();
Instance &getFile2Instance();
// etc...
idmanager.cpp
Instance &getFile1Instance()
{
static Instance file1instance;
return file1instance;
}
Instance &getFile2Instance()
{
static Instance file2instance;
return file2instance;
}
// etc...
In each file, place at the start
#include "idmanager.h"
and you can get the static Instance of any file in the obvious way.
This is as simple as it can possibly get, so copying it into your project simply can't cause a problem.
If the above example worked, then try making it slightly closer to the original answer: move the definitions of the getFileXInstance functions into the files themselves, and delete idmanager.cpp.
idmanager.h
struct Instance {/*...*/};
Instance &getFile1Instance();
Instance &getFile2Instance();
// etc...
file1.cpp
#include "idmanager.h"
Instance &getFile1Instance()
{
static Instance file1instance;
return file1instance;
}
file2.cpp
// etc...
Clearly this just moves the code around between different .obj files, so should still work.
Now replace each getFileXInstance function with a struct with a single static member function, getInstance, as follows:
idmanager.h
struct Instance {/*...*/};
struct Manager1
{
static Instance &getInstance(); // defined in file1.cpp
};
struct Manager2
{
static Instance &getInstance(); // defined in file2.cpp
};
// etc...
file1.cpp
#include "idmanager.h"
Instance &Manager1::getInstance()
{
static Instance file1instance;
return file1instance;
}
file2.cpp
// etc...
The previous step allows us to reduce the amount of boilerplate code using templates:
idmanager.h
struct Instance {/*...*/};
template <int id>
struct Manager
{
static Instance &getInstance(); // each instantiation has its definition in a different cpp file
};
file1.cpp
#include "idmanager.h"
template <>
Instance &Manager<1>::getInstance()
{
static Instance file1instance;
return file1instance;
}
This is where linker errors are most likely to start appearing again, if they do at all.
More repetition can also be removed by putting the common code in a shared header globals.h, and communicating the preprocessor constant FILEID to it.
idmanager.h
struct Instance {/*...*/};
template <int id>
struct Manager
{
static Instance &getInstance(); // each instantiation has its definition in a different cpp file
};
file1.cpp
#include "idmanager.h"
#define FILEID 1
#include "globals.h"
globals.h
template <>
Instance &Manager<FILEID>::getInstance()
{
static Instance theInstance;
return theInstance;
}
This last example is now the same as the original answer, with a few differences (no factories, no enums, no getThisFileInstance()) which are irrelevant to the linker errors. Therefore (assuming the first example worked) you can identify which change broke the program, and that should help to diagnose the real problem.
(note: although your error is exactly that which would appear if multiple files shared the same id, from the comments I assume this is not the case.)

Polymorphic DLL exports

I am currently working on a project that uses a DLL and an application that uses the DLL. The DLL is exported as an abstract base class header and a concrete implementation derived from the abstract base, as usual:
---- TaskInterface.h ----
class Task {
public:
virtual int func1(void) = 0;
virtual int func2(void) = 0;
};
extern "C" __declspec(dllexport) Task * APIENTRY newTask();
--- Task.h ---
class TaskImpl : public Task
{
public:
virtual int func1(void);
virtual int func2(void):
};
Task * APIENTRY newTask()
{
return static_cast<Task*>( new TaskImpl );
}
--- Task.cpp ---
int TaskImpl::func1(void)
{
// ...
}
int TaskImpl::func2(void)
{
// ...
}
This works so far as intended, the application includes "AbstractTask.h" and then calls the respective function defined by class TaskImpl:
--- TheApplication.cpp ---
Task aTask = newTask();
aTask->func1();
aTask->func2();
// ...
However, now the Application discovers that what the default implementation in class TaskImpl does is not enough and therfore defines within its own scope a new derived class, like so:
--- AppImpl.h ---
#include "TaskInterface.h"
class AppImpl : public Task
{
int func1(void) = { /* new stuff */ }
int func2(void) = { /* new stuff */ }
};
and then defines in TheApplication.cpp:
--- TheApplication.cpp ---
#include "AppImpl.h"
ApplImp * aNewTask = static_cast<Task*>(newTask());
aNewTask->func1();
aNewTask->func2();
In what context do you think func1() and func2() are called? Correct: It's still the concrete implementation inside the DLL class TaskImpl and not the derivates defined by class AppImpl.
And basically this is my problem: I want to use a default implementation from inside a DLL, but I want to be able to expand it on the Application side, so unless I have explicitly overriden a function in ApplImp.h, I fall back to the one defined in TaskImpl inside the DLL.
Is this possible? If so, what am I doing wrong? If not, how could I accomplish something equivalent?
I already toyed with exporting both "TaskInterface.h" and "Task.h" and then have ApplImp.h include the concrete class in the DLL, but the compile doesn't like that for obvious reasons => can't export newTask() twice.
Any help is appreciated!
As you need to allocate and deallocate via the DLL anyway, I'd suggest providing a wrapper class alongside the DLL. This wrapper class then could be designed to be inherited from.
class Task {
public:
virtual int func1(void) = 0;
virtual int func2(void) = 0;
};
// v~~~~v probably dllimport in the header you ship
extern "C" __declspec(dllexport) Task * APIENTRY newTask();
class TaskWrapper {
public:
TaskWrapper() : m_ptr( newTask() ) {}
virtual ~TaskWrapper() { deleteTask(m_ptr); }
virtual int func1(void) { m_ptr->func1(); }
virtual int func2(void) { m_ptr->func2(); }
protected: // implementation omitted for brevity
TaskWrapper(TaskWrapper const&);
TaskWrapper(TaskWrapper&&);
TaskWrapper& operator= (TaskWrapper const&);
TaskWrapper& operator= (TaskWrapper&&);
private:
Task* m_ptr; // preferably a unique_ptr
};
You could also let TaskWrapper derive from Task.
If I understand the question correctly, you want ApplImp to derive from TaskImp, and call into TaskImpl member implementations as needed, using standard C++ syntax..
You can't do that directly because the application and DLL are linked separately and have no compile-time knowledge of each other. The application doesn't know about TaskImpl at compile time, thus the compiler cannot derive from it and cannot create a Vtable that may be a combination of funcitons from application and DLL.
You chould compose the objects, i.e. create an instance of TaskImp inside ApplImp and delegate all functions to the TaskImp instance inside of ApplImp. That's inconvenient in many cases.
A more convenient way is to export the implementation of TaskImpl from the DLL: declare the whole class as __dllexport. Unfortunately, that's the least portable way to do it and in a large project, it may lead to a huge dll export section with 10000 C++-name-mangled entries. But you might be able to use TaskImpl as a base class in other DLLs or the application.
Btw, this won't compile because ApplImp is derived from Task, and Task* cannot be cast implicitly to ApplImpl.
ApplImp * aNewTask = static_cast(newTask());

Public Static Variable access

I'm tring to expose a static variable. I have tried doing this as both just a public static, and using access functions, but when I use the command Stage::SetFramework( this ); in my Framework class, or even if I make systemFramework public and use Stage::systemFramework = this, I get:
framework.obj||error LNK2001: unresolved external symbol "public: static class Framework * Stage::systemFramework" (?systemFramework#Stage##2PAVFramework##A)|
I'm not sure why this isn't working. I'm obviously missing something Can anyone help please?
#pragma once
#include "event.h"
#ifndef Framework
class Framework;
#endif // Framework
class Stage
{
protected:
static Framework* systemFramework;
public:
// static Framework* systemFramework;
// Stage control
virtual void Begin() = 0;
virtual void Pause() = 0;
virtual void Resume() = 0;
virtual void Finish() = 0;
virtual void Event(FwEvent *e) = 0;
virtual void Update() = 0;
virtual void Render() = 0;
static void SetFramework( Framework* FrameworkObject )
{
systemFramework = FrameworkObject;
};
/*
static Framework* GetFramework()
{
return systemFramework;
};
*/
};
Thanks
Listing static class data members in a class only declares them. They must still be defined somewhere. Put this definition into one .cpp file:
Framework *Stage::systemFramework;
That's because you need a FrameWork* Stage::systemFramework; somewhere too (in a .cpp file, typically). This "places" your variable you may, for example for caching reasons, have it next to some othver variables - so the compiler won't just throw it anywhere, so the declaration inside the class definition is just that, a declaration that "there will be one of these variable somewhere". [Or in an embedded system, there may be some part of memory that is backed up by battery power and another part of memory that isn't, and again, where you "place" the variable will matter in this case].
Of course, the public, private or protected inside the class will still determine which parts of the code can access the variable.