C++. Namespaces. Keywords namespace, using

Namespaces. Keywords namespace, using. Namespace creation rules. Global namespace


Contents


Search other resources:

1. The notion of a namespace. Namespace declaration. The namespace keyword. Specifying a named and unnamed namespace

Before the advent of namespaces, one single global space was used. This space contained a list of public global variables and functions that could be used in your program. If the program declared its own functions, whose names coincided with the names of the functions of the global namespace (for example, the functions abs(), sqrt(), etc.), then the names of these local functions overlapped the global ones. This caused inconvenience and required more careful attention to the choice of names. This caused inconvenience and required more careful attention to the choice of names. Also, the problem of choosing names arose when using several third-party libraries at the same time.

To make it easier to use names in C++ applications, the concept of a namespace has been introduced. Namespace is an area of definition for variables, types, constants, and functions, combined into a single or unnamed block. A namespace is denoted using the namespace keyword, and in the most general case is declared as follows:

namespace Name
{
  // Declaration of variables, constants, types, functions
  // ...
}

After declaring a namespace, you can access its elements. A namespace name may be omitted if the name is declared in the same namespace.

Outside the namespace, the call is as follows

Name::item

where

  • Name – the name of declared namespace;
  • item – the name of the element (function, class, constant, variable) that is declared in the namespace.

A namespace can be declared without a name with the following syntax

namespace
{
  // namespace constituents
  // ...
}

From a placement point of view, a namespace can be declared:

  • in one module;
  • in several modules (see examples below).

 

2. An example of declaring and using a namespace. All elements are placed in a single module

The example declares the MATH namespace, which contains the following declarations:

  • the Pi constant;
  • function Circumference() – returns the circumference based on a given radius;
  • function AreaCircle() – returns the area of a circle based on a given radius;
  • function VolumeSphere() – returns the volume of the sphere based on a given radius.

The main() function demonstrates access to some of the members of the MATH namespace.

#include <iostream>
using namespace std;

// The namespace MATH
namespace MATH
{
  // Constant in namespace
  const double Pi = 3.1415;

  // A function that returns the circumference of a circle
  double Circumference(double r)
  {
    return 2 * Pi * r;
  }

  // A function that returns the area of a circle
  double AreaCircle(double r)
  {
    return Pi * r * r;
  }

  // A function that returns the volume of a sphere
  double VolumeSphere(double r)
  {
    return 4.0 / 3 * Pi * r * r * r;
  }
}

void main()
{
  cout << "Pi = " << MATH::Pi << endl;
  cout << "V = " << MATH::VolumeSphere(3) << endl;
}

 

3. The using directive. Access to namespace elements

In order to increase the readability of the program and avoid constant specification of the namespace name when accessing its elements, the using directive is used. This directive can be applied in two cases:

using namespace Name; // include the namespace
using Name::member;   // including a single element

here

  • Name – the namespace name;
  • member – the name of the namespace element. An element can be a constant, a function, a class, and so on.

In the first case, the entire namespace is included. Once connected, the members of this namespace can be accessed directly without the need for a Name:: fragment.

In the second case, a separate namespace element is included. After connection, you can specify the name of this element directly without specifying the Name:: fragment.

 

3.1. An example of accessing all elements of a namespace

The example declares the MATH namespace. Then, for demonstration purposes, this namespace is included with the line

using namespace MATH;

In the body of the main() function, there is a call to the components of the MATH namespace (the Pi constant, the VolumeSphere() function). The call occurs without specifying the MATH:: prefix.

#include <iostream>
using namespace std;

// The namespace MATH
namespace MATH
{
  // Constant in namespace
  const double Pi = 3.1415;

  // A function that returns the circumference of a circle
  double Circumference(double r)
  {
    return 2 * Pi * r;
  }

  // A function that returns the area of a circle
  double AreaCircle(double r)
  {
    return Pi * r * r;
  }

  // A function that returns the volume of a sphere
  double VolumeSphere(double r)
  {
    return 4.0 / 3 * Pi * r * r * r;
  }
}

using namespace MATH;

void main()
{
  // Accessing members of the MATH namespace without specifying MATH::
  cout << "Pi = " << Pi << endl;
  cout << "V = " << VolumeSphere(3) << endl;
}

Program result

Pi = 3.1415
V = 113.094

 

3.2. Example of accessing an individual element in a namespace

The example declares the Operations namespace and shows access to the Sub2() and Mul2() methods of this namespace from the main() function.

#include <iostream>
using namespace std;

// A namespace that defines the basic operations on two numbers
namespace Operations
{
  double Add2(double a, double b)
  {
    return a + b;
  }

  double Sub2(double a, double b)
  {
    return a - b;
  }

  double Mul2(double a, double b)
  {
    return a * b;
  }

  double Div2(double a, double b)
  {
    if (b == 0)
      return 0;
    return a / b;
  }
}

// Implement access to Sub2() and Mul2() methods
using Operations::Sub2;
using Operations::Mul2;

void main()
{
  double x = 10, y = 8;
  double z = Sub2(x, y); // z = 2
  cout << "z = " << z << endl;

  z = Mul2(x, y);
  cout << "z = " << z << endl;

  // Error, access denied
  // z = Add2(x, y); // identifier Add2 is undefined
}

Program result

z = 2
z = 80

In the above example, methods are connected with the help of using directive

using Operations::Sub2;
using Operations::Mul2;

These methods can then be called directly without using the Operations:: prefix. If you try to call the unconnected method Add2()

// Error, access denied
z = Add2(x, y);

then the compiler will generate an error message

identifier Add2 is undefined

 

4. Global namespace ::

The global namespace defines the scope of the highest level. In this scope, global variables, types, functions, etc. can be declared.

To access the global namespace, you must use the scope extension operator ::. If there are matching names in the global namespace and some local namespace, then the use of the :: operator is required to access the global name.

Example.

The example declares:

  • the global function ShowPi(), which displays the value of the Pi number;
  • the MathItems namespace containing some constants and the ShowPi() function, whose name is the same as the name of the global function.

The main() function demonstrates access to the functions with the same name.

 

#include <iostream>
using namespace std;

// Global function that outputs the value of Pi
void ShowPi()
{
  cout << "Pi = 3.1415" << endl;
}

// The namespace in which constants and functions are defined
namespace MathItems
{
  const double Pi = 3.1415;
  const double E = 2.71828;

  // A function that displays the value of Pi from the namespace
  void ShowPi()
  {
    cout << "MathItems::Pi = " << Pi << endl;            
  }
}

using namespace MathItems;

void main()
{
  // 1. Calling the global function ShowPi()
  ::ShowPi();

  // 2. Calling the ShowPi() function from the MathItems namespace
  MathItems::ShowPi();

  // 3. Error - ambiguous call to an overloaded function
  //ShowPi(); // ambiguous call to overloaded function
}

Program result

Pi = 3.1415
MathItems::Pi = 3.1415

If in the above code in the main() function try to implement a call

// Error - ambiguous call
ShowPi();

then the compiler will generate an error

ambiguous call to overloaded function

This is logical, since it is not known which ShowPi() function is being called.

 

5. Redeclaring a namespace. Example

A namespace can be made up of parts. These parts may be declared in one or more modules. In the most general case, the partitioning of the namespace looks like this

namespace Name
{
  // Part 1. Components declaration
  // ...
}

namespace Name
{
  // Part 2. Components declaration
  // ...
}

...

namespace Name
{
  // Part N. Components declaration
  // ...
}

Example.

The example implements the Operations namespace with several functions. This namespace is split into 2 parts.

#include <iostream>
using namespace std;

// Namespace that defines basic operations on two numbers
namespace Operations
{
  double Add2(double a, double b)
  {
    return a + b;
  }

  double Sub2(double a, double b)
  {
    return a - b;
  }
}

namespace Operations
{
  double Mul2(double a, double b)
  {
    return a * b;
  }

  double Div2(double a, double b)
  {
    if (b == 0)
      return 0;
    return a / b;
  }
}

void main()
{
  // Calling functions from different parts of the Operations namespace
  cout << Operations::Add2(5, 8) << endl;
  cout << Operations::Mul2(5, 8) << endl;
}

 

6. Namespace declaration in different files (modules)

The namespace can be split into multiple files. In other words, the declaration of a namespace and its constituents may be in different files. In the most general case, the declaration of a namespace named Name in different files looks like this:

File 1.

using namespace Name
{
  // Components of namespace in file 1
  // ...
}

File 2.

using namespace Name
{
  // Components of namespace in file 1
  // ...
}

File N.

using namespace Name
{
  // Components of namespace in file N
  // ...
}

Example.

Let two modules be given:

  • Source.cpp module containing the declaration of the first part of the Operations namespace and the main() function;
  • Operations.h module, which declares the second part of the Operations namespace.

In this case, the text of both namespaces is as follows.

Module Source.cpp.

#include <iostream>
#include "Operations.h"
using namespace std;

// The namespace that defines the basic operations on two numbers,
// the first part of the namespace
namespace Operations
{
  double Add2(double a, double b)
  {
    return a + b;
  }

  double Sub2(double a, double b)
  {
    return a - b;
  }
}

void main()
{
  // Calling functions from different parts of the Operations namespace
  // From the current module
  cout << Operations::Add2(5, 8) << endl;

  // From module Operations.h
  cout << Operations::Mul2(5, 8) << endl;
}

Module Operations.h.

#pragma once

// The second part of the Operations namespace
namespace Operations
{
  double Mul2(double a, double b)
  {
    return a * b;
  }

  double Div2(double a, double b)
  {
    if (b == 0)
      return 0;
    return a / b;
  }
}

 

7. The namespace std

In classic C++, the base namespace is the std namespace. This namespace implements the facilities of the C++ Standard Library.

The standard library implements thousands of functions that are useful in the development of any programs. Examples of such functions are the mathematical functions abs(), acos(), sin(), cos() and others. A detailed discussion of the capabilities of the C++ Standard Library is beyond the scope of this topic.

In previous versions of C++, the entire standard library was in the global namespace. Placing the standard library in the std namespace greatly reduces the possibility of name collisions.

To include the std namespace, use the line

using namespace std;

It is also common in programs to refer to elements of the std namespace with the full name, for example

// square root
double a = std::sqrt(28);

// the absolute value of a number
int x;
x = std::abs(-18);

 

8. Nested namespaces

Namespaces can be nested. This means that one namespace can include another namespace. In this case, the nested namespace and its constituents can be accessed in the usual way using the :: operator.

Example.

The example declares two namespaces:

  • OUT is the external namespace;
  • IN is a namespace that is nested within the OUT namespace.

The main() function demonstrates access to the members of the OUT and IN namespaces.

#include <iostream>
using namespace std;

// Nested namespaces
namespace OUT
{
  void MethodOut() { }
  int var_out;

  namespace IN
  {
    int var_in = var_out;

    void MethodIn()
    {
      MethodOut();
      var_out = 3;
      cout << "var_out = " << var_out << endl;
    }
  }
}

void main()
{
  // use of operator ::
  OUT::IN::var_in = 35;
  OUT::IN::MethodIn();

  // after this line
  using namespace OUT;
  IN::var_in = 333;
  cout << "IN::var_in = " << IN::var_in << endl;

  // after this line
  using namespace OUT::IN;
  MethodIn(); // you can call the method directly
}

Program result

var_out = 3
IN::var_in = 333
var_out = 3