Let's back up a bit...
This is easier to visualize with functions. So let's start there. Global variables work the exact same way.. and I'll explain those below.. so bear with me here.
When you create a function in a source file, that function is only declared in that source file. However the name of the function is externally linked so that other source files can link to it.
For example:
1 2 3 4 5 6 7 8
|
// a.cpp
#include <iostream>
using namespace std;
void func()
{
cout << "func in a.cpp" << endl;
}
| |
1 2 3 4 5 6 7 8
|
// b.cpp
#include <iostream>
using namespace std;
void func()
{
cout << "func in b.cpp" << endl;
}
| |
Try to link these 2 files together and you'll get a "multiple defined" linker error, because you have
two different functions with the same name. If you call func(), which version are you intending to call? a.cpp's version or b.cpp's version?
Makes sense, right? So what if you move the function to a header file:
1 2 3 4 5 6 7
|
// header.h
#include <iostream>
void func()
{
std::cout << "func in header.h" << std::endl;
}
| |
1 2
|
// a.cpp
#include "header.h"
| |
1 2
|
// b.cpp
#include "header.h"
| |
Same problem here. But why? You only have one function, right? So why is it saying "multiple defined"?
Well, it's because #include basically works like a glorified copy/paste operation (it's more complex than that, but conceptually that's a good way to think of it). When you include header.h, you are effectively copy/pasting the entire contents of the header into this source file.
As a result... you have the same problem as illustrated above. Both a.cpp and b.cpp are including the header... so both are copy/pasting their own copy of func()... therefore func() has a body in multiple cpp files and the linker doesn't know which version you want to use. So it spits out that error.
There are a few ways to solve this problem. The most common is to make sure func() only exists in one cpp file. But still make it accessible in other cpp files by putting a prototype in a header file. Example:
1 2 3 4 5 6
|
// header.h
void func(); // a note for the compiler. This does not actually create the function,
// it just tells the compiler "func" is a function name... so it's OK to call it
// and the linker will have this function defined somewhere, so don't worry
// about it
| |
You can include this header in any number of files now without problem. The prototype does not actually create a function body, it's just a note to the compiler to allow the name 'func' to be recognized. You can then put that function body in
one and only one cpp file, and the linker will tie it together with all other source files in the project.
Note however, that you need to actually put the body
somewhere. If you don't put a function body somewhere in the code, you'll get "unresolved external symbol" errors from the linker. After all, how can you call a function that was never defined?
Hopefully that makes sense. Assuming it does....
Global variables are exactly the same.
int var;
This is the variable equivalent of a function body. You are creating a new variable, and reserving memory for it. So back to the original example:
This will give you multiple definition errors just like the function example did. You now have 2 variables with the same name, and the linker doesn't know which one you are intending to use.
Move 'var' to a header and #include it multiple places and it solves nothing... because #include just copy/pastes the definition into multiple files.
So to solve this... you need some way to make a "prototype"... similar to how you can have a function prototype that isn't actually a body, yet tells the compiler it's OK to treat "var" as a variable name... and tells the linker "don't worry, 'var' will be defined somewhere".
The way to do that with variables is the
extern
keyword:
This is like a "variable prototype". It does not actually define the variable. It's a note to the compiler saying "var is a variable name, but it's not defined here. It's defined elsewhere and the linker will fill it in for you."
So this is OK to #include in any number of source files. Each source file will not be creating their own copy of the variable... but will just be referencing a variable that will be externally linked by the linker.
But, as with functions, you still need to give the variable a "body". This means you have to define it (without extern) in
one and only one source file. If you fail to do this, you will get unresolved external errors, just like you would if you don't give a function a body. After all.... how can you use a variable that was never defined?
So:
1 2
|
//header.h
extern int var; // prototype the var
| |
1 2
|
// one_and_only_one_source_file.cpp
int var; // give it a body
| |
That's it. The
const
keyword is irrelevant to this topic and does not change this fundamental behavior.
The
static
keyword does... but that's another topic that I won't get into here (though if you're interested I can explain it).