Our previous lesson explained the core purpose of namespaces. They are a way to organise and group related code together, such as a collection of functions that relate to maths.
In this way, they have similar a organisational purpose to classes. The main conceptual differences is that classes can also create objects.
It doesn't make sense to create an object with a type of "Math". So, for this type of organisation, we can create a namespace instead.
Those coming from other programming languages may be familiar with the concept of a static class, which is how these problems are sometimes solved in those programming languages.
C++ also allows class members to be static, which we'll cover soon.
However, in most scenarios, solving this problem directly using namespaces tends to be the preferred approach in C++.
With classes, we saw the convention of provide the declaration of our class in a header file, and then provided the definition of its functions within a separate cpp file.
We can apply this exact same pattern when using namespaces:
// Math.h
#pragma once
namespace Math {
float Pi { 3.14f };
int Add(int x, int y);
float Circumference(float Diameter);
class Square {
float SideLength;
float Area();
};
}
// Math.cpp
#include "Math.h"
int Math::Add(int x, int y) {
return x + y;
}
float Math::Circumference(float Diameter) {
return Diameter * Pi;
}
float Math::Square::Area() {
return SideLength * SideLength;
}
Classes have a useful property where we can have a "private" section. Here, we can store helper functions and variables that we want to keep hidden from the outside world.
Namespaces do not have access specifiers - everything in a namespace can be considered public.
However, we can solve the same problem using an anonymous namespace.
Predicatably, an anonymous namespace is a namespace without a name:
namespace {
int SomeNumber { 4 };
}
Variables and functions defined within an anonymous namespace are only available to the same source file where the namespace exists.
Therefore, we can think of an anonymous namespace as the "private" section of a file.
Following on from our previous Math
example, lets make Pi
"private".
To do that, we can remove it from our header file entirely:
#pragma once
namespace Math {
float Pi { 3.14f };
int Add(int x, int y);
float Circumference(float Diameter);
class Square {
float SideLength;
float Area();
};
}
This is already an improvement over classes - it means our namespace header files are smaller. This makes them easier to read and faster to compile when other files #include
it.
Next, we add it to an anonymous namespace in our source file:
#include "Math.h"
// Private
namespace {
float Pi { 3.14f };
}
// Public
int Math::Add(int x, int y) {
return x + y;
}
float Math::Circumference(float Diameter) {
return Diameter * Pi;
}
float Math::Square::Area() {
return SideLength * SideLength;
}
With that done, everything in our file (including our namespace functions) still have access to it, we simplified our Math
namespace, and we avoided creating a global variable.
Up next, we'll look at a simple new data type that is a powerful way of storing data that can be one of a specific set of possibilities.
Become a software engineer with C++. Starting from the basics, we guide you step by step along the way