When a project becomes large and we introduce many libraries, it is very likely that the two libraries will define classes with the same name like List, Tree, Node, etc. If the compiler does not take this into account, the programmer will call the conflict problem. The C++ standard provides namespace tools to better control the scope of names.

Traditional C++ namespaces

  • Declaration region: A declaration region is a region that can be declared. For example, a global variable can be declared outside a function, in which case its declaration area is the file in which it is declared. For variables declared in functions, the declaration area is the code block in which they are declared.
  • Potential scope: The potential scope of a variable starts at the declaration point and ends at the end of its declaration area. The potential scope is therefore smaller than the declaration area because variables are not used until they are defined.

New namespace features

C++ includes the ability to create named namespaces by defining a new declaration region. One purpose of this is to provide a region to declare names. A name in one namespace does not conflict with the same name in another namespace, while allowing other parts of the program to use things declared in that namespace. For example, create two namespaces using the keyword namespace:

namespace Jack {
    double pail;                           // variable declaration
    void fetch(a);                          // function prototype
    int pal;                               // variable declaration
    struct Well {. }// structure declaration
}

namespace Jill {
    double bucket(double n) {... };// variable declaration
    double fetch;                          // variable declaration
    int pal;                               // variable declaration
    struct Hill {. }// structure declaration
}
Copy the code

Namespaces are open, meaning you can add names to existing namespaces. For example, the following statement adds the name goose to the list of names already in Jill:

namespace Jill {
    char* goose(const char*);
}
Copy the code

Similarly, the original Jack namespace provides a prototype for the fech () function. You can use the Jack namespace again after this file (or in another file) to provide the code for the function:

namespace Jack {
    void fetch(a) {... }}Copy the code

When you need access to the name of a given namespace, you qualify the name with the namespace through the scoped resolution operator ::.

1. Using declarations and using compilation directives

When we don’t want to qualify a name every time we use it, c++ provides two mechanisms (using declarations and using compilation directives) to simplify the use of names in namespaces.

  • Using declaration: Makes the identifier of a particular declaration available
namespace Jill {
    double bucket(double n) {... }double fetch;
}
char fetch;

int main(a) {
    using Jill::fetch     // using declaration
    double fetch;         // Error! Already have a local fetch
    cin >> fetch;         // read a value into Jill::fetch
    cin >> ::fetch;       // read a value into global fetch
}
Copy the code

This code, the using declaration, adds a specific name to the declaration area to which it belongs. The using declaration in main() adds fetch to the declaration area defined by main(). Once the declaration is complete, you can use the name fetch instead of Jill::fetch.

  • Using compilation instruction: Make the entire namespace available

The using compilation directive makes all names available. Using the compilation directive in the global declaration area makes the name of that namespace globally available. Such as:

#include <iostream>
using namespace std;

// Using the compiler directive in a function makes its name available in the function
int main(a) {
    using namespace jack;   // make names available in vorn()
}
Copy the code

Different namespaces represent different memory units. Note the following ambiguities when using namespaces.

using namespace jack
using namespace jill   // Both Spaces have Pal variables

pal = 4;               // which one? now have a conflict
Copy the code

In general, it is safer to use a using declaration than a using compilation directive because it only imports the specified name. If this name conflicts with a local name, the compiler will indicate it. The using compilation directive imports all names, including some that are not really needed. If there is a conflict with a local name, the version of the namespace is locally overridden and the compiler does not issue a warning.

2. Additional features of namespaces

  • Namespaces can be nested
namespace elements {
    namespace fire {
        intflame; . }float water;
}
Copy the code

Accessing flame refers to Elements ::fire::flame. The internal name can also be made available using the using compilation directive: Using Elements ::fire

  • Use a using compilation directive and a using declaration in the namespace as follows:
namespace myth {
    using Jill::fetch;
    using namespace elements;
    using std::count;
}
Copy the code

If you want to access Jill:: Fetch, you can access it either way.

myth::fetch
Jill::fetch
Copy the code
  • Transitivity of namespaces

Using compilation instructions can be passed. If A op B and B op C, then A op C.

using namespace myth;

/// The following two sentences are equivalent
using namespace myth;
using namespace elements;

// Create an alias for the namespace
namespace MEF = myth::elements::fire;
using MEF::flame;
Copy the code
  • An unnamed namespace

Is often a substitute for static variables.

static int counts       // Declare static storage, internal linkage

/ / / is equivalent to
namespace {
    int counts          // static storage, internal linkage
}
Copy the code