Introduction to namespaces in C++ programming

  • 2020-05-07 20:06:49
  • OfStack

A namespace is a declarative region that provides a scope for its internal identifiers (the names of types, functions, variables, and so on). Namespaces are used to organize code into logical groups and can also be used to avoid name collisions, especially if the base code includes multiple libraries. All identifiers within a namespace scope are visible to each other without any restrictions. Identifiers outside the namespace can be obtained by using the fully qualified name of each identifier (for example, std::vector) < std::string > vec;) Members can also be accessed by the using declaration for a single identifier (using std::string) or the using directive for all identifiers in the namespace (C++) (using namespace std;) To access the members. The code in the header file should always use a fully qualified namespace name.
The following example demonstrates three ways that a namespace declaration and code outside the namespace can access its members.


namespace ContosoData
{ 
 class ObjectManager 
 {
 public:
  void DoSomething() {}
 };
 void Func(ObjectManager) {}
}

Use fully qualified names:


ContosoData::ObjectManager mgr;
mgr.DoSomething();
ContosoData::Func(mgr);

Use the using declaration to bring 1 identifier into the scope:


using WidgetsUnlimited::ObjectManager;
ObjectManager mgr;
mgr.DoSomething();

Use the using directive to bring everything in the namespace into scope:


using namespace WidgetsUnlimited;
ObjectManager mgr;
mgr.DoSomething();
Func(mgr);

using instruction
USES the using directive to use all names in a namespace without requiring the namespace name to be an explicit qualifier. If multiple different identifiers are used in one namespace, the using directive (that is, *.cpp) is used in the implementation file. If you use only one or two identifiers, consider using declarations to bring in only those identifiers, not all of the identifiers in the namespace. If the name of the local variable is the same as the name of the namespace variable, the namespace variable is hidden. It is an error for a mission namespace variable to have the same name as a global variable.
note
The
using directive can be placed at the top of the.cpp file (within the scope of the file) or within a class or function definition.
In general, avoid placing the using directive in a header file (*.h), because any file that contains this header will bring everything in the namespace into scope, which can lead to name hiding and name collisions that are very difficult to debug. In the header file, always use the fully qualified name. If these names are too long, you can shorten them with namespace aliases. (see below.)
declares namespaces and namespace members
typically declares a namespace in the header file. If the function implementation is in a separate file, qualify the function name, as shown in this example.


//contosoData.h 
#pragma once
namespace ContosoDataServer
{
 void Foo();
 int Bar();

}
contosodata.cpp  The implementation of the function should use the fully qualified name, even if it will 1 a  using  The same is true for instructions placed at the top of the file: 
#include "contosodata.h"
using namespace ContosoDataServer; 

void ContosoDataServer::Foo()
{
 //no qualification because using directive above
 Bar(); 
}

int ContosoDataServer::Bar(){return 0;}

Namespaces can be declared in multiple blocks in a single file, or in multiple files. The compiler joins the parts in 1 during preprocessing, and the resulting namespace contains all the members declared in all the parts. A related example is the std namespace declared in each header file in the standard library.
Members of a specified namespace can be defined outside of the declared namespace explicitly qualified by the defined name. However, the definition must appear after the declared location in the namespace, which is contained in the declared namespace. Such as:


// defining_namespace_members.cpp
// C2039 expected
namespace V {
  void f();
 }

 void V::f() { }  // ok
 void V::g() { }  // C2039, g() is not yet a member of V

 namespace V {
  void g();
 }
}

This error can occur when namespace members are declared across multiple header files and these headers are not included in the correct order.
global namespace
is part 1 of the implicit global namespace if an identifier is not declared in the explicit namespace. In general, try to avoid declarations in the global scope if possible, except for the entry point main function, which must be in the global namespace. To explicitly qualify a global identifier, use a scope resolution operator without a name, such as ::SomeFunction(x); As shown in. This will distinguish the identifier from anything with the same name in any other namespace, and also help make your code easier for others to understand.
Std namespace
all C++ standard library types and functions are declared in the std namespace or in a namespace nested within std.
nested namespaces
can nest namespaces. Normal nested namespaces have unqualified access to their parent members, while the parent member does not have unqualified access to the nested namespace (unless it is declared inline), as shown in the following example:


namespace ContosoDataServer
{
 void Foo(); 

 namespace Details
 {
  int CountImpl;
  void Ban() { return Foo(); }
 }

 int Bar(){...};
 int Baz(int i) { return Details::CountImpl; } 

}

Common nested namespaces can be used to encapsulate the internal implementation details of part 1 of a public interface that is not part of a parent namespace.
inline namespace (C++ 11)
is different from a normal nested namespace in that members of an inline namespace are treated as members of the parent namespace. This 1 feature enables parameter-dependent lookups for overloaded functions to work with overloaded functions in parent namespaces and nested inline namespaces. It also allows you to declare specialization in the parent namespace of a template declared in an inline namespace. The following example shows how external code is bound to an inline namespace by default:


//Header.h
#include <string>


namespace Test
{
 namespace old_ns
 {
  std::string Func() { return std::string("Hello from old"); }
 }

 inline namespace new_ns
 {
  std::string Func() { return std::string("Hello from new"); }
 }
}

#include "header.h"
#include <string>
#include <iostream>

int main()
{
 using namespace Test;
 using namespace std;

 string s = Func();
 std::cout << s << std::endl; // "Hello from new"
 return 0;
}

The following example shows how to declare specialization in the parent namespace of a template declared in an inline namespace:


namespace Parent
{
 inline namespace new_ns
 {
   template <typename T>
   struct C
   {
    T member;
   };
 }
  template<>
  class C<int> {};
}

 

Inline namespaces can be used as a version control mechanism to manage changes to the library's public interface. For example, you can create a single parent namespace and wrap each version of an interface into its own namespace nested within the parent namespace. The namespace for the latest or preferred version is limited to inline and is therefore exposed as a direct member of the parent namespace. The client code that calls Parent::Class is automatically bound to the new code. By using a fully qualified path that points to the nested namespace containing the code, clients that choose to use the older version can still access it.
The Inline keyword must be applied to the first declaration of the namespace in the compilation unit.
The following example demonstrates two versions of an interface, each in a nested namespace. Some changes are made to the v_20 namespace through the v_10 interface, and the namespace is marked inline. Using the new library and call Contoso: : Funcs: : Add client code will call v_20 version. Try to call Contoso: : Funcs: : Divide code will now get a compile-time error. If they do require this function, they can still access the v_10 version by explicitly calling Contoso::v_10::Funcs::Divide.


namespace Contoso
{
 namespace v_10
 {
  template <typename T>
  class Funcs
  {
  public:
   Funcs(void);
   T Add(T a, T b);
   T Subtract(T a, T b);
   T Multiply(T a, T b);
   T Divide(T a, T b);
  };
 }


 inline namespace v_20
 {
  template <typename T>
  class Funcs
  {
  public:
   Funcs(void);
   T Add(T a, T b);
   T Subtract(T a, T b);
   T Multiply(T a, T b);
   std::vector<double> Log(double);
   T Accumulate(std::vector<T> nums);
  };
 }
}


namespace alias
The
namespace names must be unique, which means that they should not be too short in general. If the length of the name makes the code difficult to read, or if typing in a header file that does not use the using directive is tedious, you can use a namespace alias that is used as an abbreviation of the actual name. Such as:


ContosoData::ObjectManager mgr;
mgr.DoSomething();
ContosoData::Func(mgr);
0

anonymous or unnamed namespaces
can create an explicit namespace without giving it a name:


ContosoData::ObjectManager mgr;
mgr.DoSomething();
ContosoData::Func(mgr);
1

This is called an unnamed or anonymous namespace, and is useful when you want to make variable declarations invisible to code in other files (that is, to provide internal links to them) without having to create named namespaces. All the code in the same 1 file can see the identifiers in the unnamed namespace, but these identifiers and the namespace itself are not visible outside of the file (or, more accurately, outside of the translation unit).


Related articles: