Sign in to follow this  
BiiXteR

Using a extern variable for a object causes linker errors

Recommended Posts

What I'm trying to do is to make my "Window" object accessible to a class which doesn't have access to it, so that it can use it however it wants.

I did some research and the best way seems to be to use extern (but then again, I'm really confused so I could be really wrong).

 

However, when i try to call a function in my "Window" object, from the file that uses it externally, I get linker errors : 

 

f1b99bd678665580c189d8d2605007fa.png

 

2880e4f93319fee2aed62d4dfe116653.png

 

 

Here's the code I have : 

 

main.cpp :

#include <Engine/Engine.h>
#include "Engine\Global_Variables.h"

int main()
{

	Engine coreEngine;
	coreEngine.Initialize();

	std::cout << window.GetCurrentVSyncStatus() << std::endl;

	system("pause");

	coreEngine.Run();

	return 0;

}

Global_Variables.h :

#pragma once

#include "Engine.h"

extern Window window;

So, since main.cpp has included Global_Variables.h it should be able to the external Window object, right? (at least according to my logic)

 

Engine.h :

#pragma once

#include "Window.h"

class Engine
{
public:
	
	Engine();

	void Initialize();
	void Run();
	void Update();

	Window window;

private:

};


Here's the "original" version of the Window object.

 

The linker errors appear to get fixed when I remove the 7th line in main.cpp : 

std::cout << window.GetCurrentVSyncStatus() << std::endl;

This is where it's trying to use the original variable, trough the external variable located in Global_Variables.h.

 

Firstly, I can't understand how the external variable in Global_Variables.h knows which variable it should "copy", aka how it knows that it's supposed to "copy" the variable in Engine.h.

 

And my second question is, how come I get the linker errors?

 

To me, it seems like the external variable, cannot make a copy of the original variable, and therefore linker errors. But I have no idea.

Maybe it's not even because of the external variable.

Share this post


Link to post
Share on other sites

What I'm trying to do is to make my "Window" object accessible to a class which doesn't have access to it, so that it can use it however it wants.


Why? Without more context that sounds like terrible design, but if you really want to do this, you will probably want to use a pointer of some variation. Here is how you do it with a raw pointer:
 
// in global_variables.h
extern Window* window; // note that this is a pointer, and that this is a declaration, not a definition

// in main.cpp
Window* window = nullptr; // this is the definition
int main()
{
    Engine coreEngine;
    window = &coreEngine.window; // point the global at the window in coreEngine; 

    // run the game here...
}
But why do you want to do this? What do you think this approach will get you?
 

Firstly, I can't understand how the external variable in Global_Variables.h knows which variable it should "copy", aka how it knows that it's supposed to "copy" the variable in Engine.h.


It doesn't. The global "window" and Engine::window aren't the same thing - Engine::window isn't even static, so it won't even exist unless you create an instance of an Engine. You're getting linker errors because you need to actually define the global "window" at the global scope in some translation unit if you want to reference it. If you declare it but don't reference it, then the linker will ignore it.

The compiler can't read your mind, it doesn't know that you intend ::window and Engine::window to be the same thing. ;) Edited by Oberon_Command

Share this post


Link to post
Share on other sites

 

What I'm trying to do is to make my "Window" object accessible to a class which doesn't have access to it, so that it can use it however it wants.


Why? Without more context that sounds like terrible design, but if you really want to do this, you will probably want to use a pointer of some variation. Here is how you do it with a raw pointer:
 
// in global_variables.h
extern Window* window; // note that this is a pointer, and that this is a declaration, not a definition

// in main.cpp
Window* window = nullptr; // this is the definition
int main()
{
    Engine coreEngine;
    window = &coreEngine.window; // point the global at the window in coreEngine; 

    // run the game here...
}
But why do you want to do this? What do you think this approach will get you?
 

Firstly, I can't understand how the external variable in Global_Variables.h knows which variable it should "copy", aka how it knows that it's supposed to "copy" the variable in Engine.h.


It doesn't. The global "window" and Engine::window aren't the same thing - Engine::window isn't even static, so it won't even exist unless you create an instance of an Engine. You're getting linker errors because you need to actually define the global "window" at the global scope in some translation unit if you want to reference it. If you declare it but don't reference it, then the linker will ignore it.

The compiler can't read your mind, it doesn't know that you intend ::window and Engine::window to be the same thing. ;)

 

 

Why is it a bad design?

I'm just trying to use that variable, from other classes/files.

I'm guessing there are better ways to do this? :o

 

And also, the piece of code you "supplied" kind of confuses me. (If it's obvious and it shouldn't confuse me, I'll blame it on being tired ^_^ )

 

You declare the extern variable in the "Global_Variables.h" file, but you don't use it anywhere else.

However, on the 9th line : 

window = &coreEngine.window; // point the global at the window in coreEngine; 

You use the Window variable you created in main.cpp (line 5), to point the global at the window in coreEngine, but I can't understand how this has any effect on the global variable since it's not included, and if it was you would have 2 variables with the same name? o.O

Share this post


Link to post
Share on other sites
extern is essentially telling the compiler "this is declared elsewhere". You have to then declare the instance somewhere, usually in a cpp file.

Thing.h
extern int foo;

Thing.cpp
int foo = 123;

Anything including Thing.h can now access foo.

Share this post


Link to post
Share on other sites

 

Why is it a bad design?


Having globals is usually considered bad design, with the exception of a few special cases. It's bad design because it can make tracking what code depends on what more difficult to follow and it makes it too easy for code to touch other code, which leads to your codebase turning into a big ball of spaghetti, among other negative things. Most good code references as few other bits of code as possible so that it can be understood and tested in isolation.
 

I'm just trying to use that variable, from other classes/files.
I'm guessing there are better ways to do this? :o


Yes. Usually you would make the dependency explicit by passing the variable the other class wants to use to the class itself.
 

You declare the extern variable in the "Global_Variables.h" file, but you don't use it anywhere else.
However, on the 9th line : 

window = &coreEngine.window; // point the global at the window in coreEngine; 
You use the Window variable you created in main.cpp (line 5), to point the global at the window in coreEngine, but I can't understand how this has any effect on the global variable since it's not included,

 


I don't need to include it. I provided the actual definition of the variable. extern declarations are just statements to the compiler that a global variable exists somewhere with a particular type and name. They don't actually define the variable - the reason you were getting linker errors was because you didn't provide a definition of the variable in your program anywhere.
 

and if it was you would have 2 variables with the same name? o.O


They do appear to have the same name, but they aren't the same variable. One is a global variable, the other is an instance variable on a class. The former's "proper" name (ie. the name that the compiler sees) is ::window, the latter's is "Engine::window". If you really wanted, you could also have a local variable and a function argument named "window," eg.
 
extern Window window; // global, but not defined in this translation unit - true name is ::window
Window window; // global, defined in this translation unit - true name is ::window, the extern above references this one
namespace N
{
    Window window; // also a global, but lives in a namespace - true name is N::window
}
class Engine
{
public:
   static Window window; // class variable - also a global, but is a part of the Engine class - true name is Engine::window
   Window window; // instance variable - true name is ALSO Engine::window, but lives on an instance not the class itself
};

void DoSomethingWithAWindow(Window& window) // function argument
{
   Window window; // local variable
}
C++ sees all of these windows as different variables. I would recommend against using the same name for multiple variables in order not to confuse yourself.

 

 

Ohh, I see. Now I understand, thanks a lot for the help! :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this