0

I'm making a c++ OpenGL project and I'm having trouble with static variables.

I have a header "Scene.h" like so:

#pragma once

#include "A.h"

class Scene
{
    //class body
};

static Scene* active = new Scene();

And my A.h file looks like this:

#pragma once

#include "Scene.h"

class A
{
    active->SomeMethod(); //Here I get error C2065: undeclared identifier
};

In my source file I have included only my Scene.h, since it includes A.h already, and I have no problem there.

I have also tried to use a static Scene object like so:

class Scene
{
    static Scene* active;
};

And then to access it like so:

Scene::active->DoSomething();

But then I get error C2653: Scene is not a class or namespace name. I read somewhere that to do this I need precompiled headers, and that is no option for me.

What is the correct way to have a static pointer in this case?

whatabouthis
  • 63
  • 1
  • 4
  • 1
    The class definition contains members of the class, not `active->SomeMethod();` (whatever that is meant to be) – M.M Dec 06 '19 at 08:00
  • 1
    If you want `static` variables in header, make them `inline static`. However, I really believe you want `inline extern Scene* active = new Scene();`. – Scheff's Cat Dec 06 '19 at 08:00
  • 1
    The best way to deal with static variables in system programming languages is to only have values that are read-only. Right now you're experiencing linking issues and more. There is also no good way to write unit tests for code that deals with static variables. If you need variables that can be modified at runtime, I advise to never give them static lifetime. For debugging purposes, sure, but otherwise it is bad practice. Small fact : in `Rust` the compiler with default settings will only allow read-only variables to have static lifetime. – Arne J Dec 06 '19 at 08:08
  • 2
    Btw. there is a circular dependency of `A.h` and `Scene.h` (that I bet is the reason of `C2653: Scene is not a class or namespace name`). Whatever is read first, reads the other which then tries to read the first but fails (due to the `#pragma once`). One of these two `#include`s has to be removed (and replaced by a forward declaration in case). Please, have a look at this: [SO: C++ circular header includes](https://stackoverflow.com/q/11971408/7478597) – Scheff's Cat Dec 06 '19 at 08:08
  • By the way, in 'C++' read-only variables start with the `const` keyword. – Arne J Dec 06 '19 at 08:14
  • Thank you for your replies. Indeed removing the circular dependency resolved the problem. I ended up passing the values I need from my scene objects to my A objects, since I removed the Scene.h from A.h. – whatabouthis Dec 06 '19 at 08:21

2 Answers2

1

If you declare a global variable static in C++, you make it internal linkage. This means, it is not visible to other compilation units, and since you want to use it in class A - which probably resides within a different source file - this is not what you want.

What you probably want is a static class member (your second example), but be aware that in addition to the declaration you need to define it:

class Scene
{
    public:
       static Scene* active;
};

Scene* Scene::active = new Scene();

Also note that members of C++ classes by default are private, so your second example is lacking the public access specifier, so A would not be able to access a private member of Scene.

As Scheff has already pointed, you're having issues with circular dependencies. If class Scene does not use A in any way, remove #include "A.h" in the "Scene.h". Otherwise move active->SomeMethod(); to the implementation of class A and use forward declaration instead of including "Scene.h" in A.h.

[edit] As a note, since you only show excerpts of your code: This answer was written under the assumption that you have a header file and a source file for Scene, and a header file and a source file for A. If you keep both Scene and A within their headers only, things will not work out because of circular dependencies. Unless you have a strong reason for going header-only, I would suggest in any case that you have a clean separation between clas declaration (header file) and implementation (source file), avoid too many mutual includes if possible and rather use forward declarations.

user826955
  • 3,137
  • 2
  • 30
  • 71
  • I am getting "explicit type is missing" when I try to put static in front of Scene::active = new Scene(). – whatabouthis Dec 06 '19 at 08:26
  • sorry, copy & paste error. I've corrected it. There shall be no `static` in the definition, but the return type (`Scene*`) instead. – user826955 Dec 06 '19 at 08:28
0

See working example (by the use of the hint from scheff) in onlineGdb.

First of all I do not recommend use of global variables! Even worse is there use at global namespace. Better design is some namespace or if applicable (acessed only from one file) definition in an anonymos namespace. Think about using the singleton-Pattern - but that does not adress your Question.

Second I do not recomend to use a raw pointer: Objects you created with new you have to destroy, but at which time you'll want to do it. If ever You stick to a pointer use some smartpointer ... - My enhancment uses an Objecte, and prove by cout the call of the destructor.

the Prob in your code is: You can't call a method inside a class definition.

Xantopp
  • 64
  • 7