After going through the same problem and doing some research I'd like to add on to the answer above! There are different ways to have shared variables, and depending on your situation you will want to use a different option.
Global Variable Declaration
The keyword extern
before a variable allows you to declare a completely global variable, that can afterwards be used throughout all your code (as long as you include the specific header where this variable is declared). Pros of this is that it is very simple to setup, but cons is that as your code gets more extensive it becomes harder to get track what these global variables mean. For this reason, it is, in general, not recommended to use global variables.
For example:
Header File - header
#ifndef HEADER_H
#define HEADER_H
extern int global_x;
void print_global_x();
#endif
Source 1 - main
#include "header.h"
// since global_x still needs to be defined somewhere,
// we define it (for example) in this source file
int global_x;
int main()
{
//set global_x here:
global_x = 5;
print_global_x();
}
Source 2 - header.cpp
#include <iostream>
#include "header.h"
void print_global_x()
{
//print global_x here:
std::cout << global_x << std::endl;
}
(Example taken from this answer)
Using a namespace
Using a global variable can be unclear in some cases. If you use it in many files, you risk forgetting where this variable came from and where it is being edited exactly. On top of that, you may have many global variables and methods, each specific to aspects of your code. Namespaces allow you to specify what each variable is related to. For example:
Header file
#ifndef HEADER_H
#define HEADER_H
#include <iostream>
namespace x_storage
{
int x;
void print_x()
{
std::cout << x << std::endl;
}
}
namespace complicated_algorithms
{
int x;
void add_10_to_x_and_print()
{
x = x + 10;
std::cout << x << std::endl;
}
}
#endif
Source 1 - main
#include "header.h"
int main()
{
x_storage::x = 3; //set x in the x_storage namespace to 3
complicated_algorithms::x = 3; // set x in complicated_algorithms namespace to 3
int x = 4; //set x in the global namespace to 4
x_storage::print_x(); // prints 3
complicated_algorithms::add_10_to_x_and_print(); // prints 13
x_storage::print_x(); // prints 3
std::cout << x << std::endl; //prints 4
}
Class with static elements
Finally, you can have a class where all elements are static. This comes in hand when you want these variables shared across all the code but these variables need to be modified constantly. This way, all the modification happens inside the class. A place where I found this useful was in my testing environment, as I have a few variables that I reuse throughout the test but I want to reset their value at the beginning of each test. Example:
Header file - Counter.h
#ifndef COUNTER_H
#define COUNTER_H
class Counter
{
public:
static int get_counter();
static void add_one();
static void reset();
private:
static int counter;
}
#endif
Source 1 - Counter.cc
int Counter::counter = 0; //must always declare even if not set to anything
int Counter::get_counter()
{
return counter;
}
void Counter::add_one()
{
counter++;
}
void Counter::reset()
{
counter = 0;
}
Source 2 - use of Counter
#include "Counter.h"
void method1()
{
Counter::reset();
if(first_condition_met()) Counter::add_one();
}
void method2()
{
if(another_condition_met()) Counter::add_one();
else Counter::reset();
}
This is a simple code where you can play with the conditions to meet to see how counter behaves given different truth tables. There are other more complicated cases where a similar approach can be very useful.