C++中的命名空间

时间:2020-02-23 14:30:01  来源:igfitidea点击:

非正式地,C++中的命名空间是一个命名范围,我们可以使用它来逻辑地组织代码。

这将确保具有相似功能的变量,函数和类在同一范围内。
不仅;它也可以帮助避免命名冲突,因为它们在命名范围内。

让我们看看如何在C++中使用名称空间来使我们的生活更轻松。

C++中的命名空间可以包含什么?

名称空间只是一个声明性代码块,它使用作用域名称(称为名称空间名称)来界定。

由于它是一个代码块,因此可以包含变量,常量,函数和类。
但这是一个声明性代码块,因此您只能使用它来定义所有变量和类。

让我们举个例子。
我们将构建一个名为" MyNamespace"的命名空间。
我们暂时将其保留为空,然后其中添加内容。

namespace MyNamespace {
}

这是声明名为" MyNamespace"的命名空间的语法。
我们可以在该块中插入所有变量等。

所以现在,我们的名称空间为空。
如果我们想对我们有用,那就添加一些成员吧!

我们如何在C++中访问名称空间的成员?

我将在此命名空间内声明一个名为int类型的变量" my_data"。

namespace MyNamespace {
  int my_data;
}

每当我们在命名空间中声明某些内容时,我们打算稍后在主程序中使用它。

如果我们尝试通过直接访问来修改" my_data",会发生什么?

namespace MyNamespace {
  int my_data;
}

int main() {
  //Try to access my_data directly will give a compilation error
  my_data = 100;
  return 0;
}

输出

test.cpp: In function ‘int main()’:
test.cpp:8:14: error: ‘my_data’ was not declared in this scope
            my_data = 100;
            ^~~~~~~
test.cpp:8:14: note: suggested alternative:
test.cpp:2:13: note:   ‘MyNamespace::my_data’
       int my_data;

编译器抱怨说它在全局范围内没有看到一个名为" my_data"的变量。
我们该如何处理?

答案在于编译器给我们的提示!

我们需要使用范围解析运算符(::),以便我们的编译器可以识别范围。

另外,这使我想到了命名范围的主题。
由于我们的名称空间具有名称,因此相应的作用域名称将是名称空间名称!

因此,我们将其与作用域解析运算符结合起来以获得MyNamespace :: my_data!而已!现在,因为我们现在可以访问此变量,所以我们可以做所有想要的事情。

让我们重写程序以使用正确的范围。

#include <iostream>

namespace MyNamespace {
      int my_data;
}

int main() {
  //Try to access my_data directly will give a compilation error
  MyNamespace::my_data = 100;
  std::cout << "Accessed MyNamespace::my_data! Assigning a value to it :" << MyNamespace::my_data << std::endl;
  return 0;
}

输出

Accessed MyNamespace::my_data! Assigning a value to it : 100

现在,我们已经解决了问题!现在,让我们转到另一个示例,以显示命名空间的另一种用例–避免名称冲突。

避免函数之间的名称冲突

由于我们提到了命名空间中所有成员的作用域是由命名空间名称定义的,因此我们可以使用它来避免重命名功能。

例如,在我们的命名空间中,假设我们定义了一个名为add(x,y)的函数以将两个数字相加。

在我们的全球范围内,我们仍然可以拥有另一个名为add(x,y),甚至add(x,y,z)的单独函数!这是因为范围不同。
我们现在不需要不必要地重命名功能!

#include <iostream>

//Example of a Namespace:
//This is used to manage function signatures so that they don't conflict
namespace MyNamespace {
  template <typename T, typename R>
      auto add(T x, R y) -> decltype(x + y) {
          return x + y;
      }
}

//Another function called add(mul, x, y), which multiplies the result of (x + y) with mul
template <typename T, typename R>
auto add(int mul, T x, R y) -> decltype(mul * (x +  y)) {
  return mul * (x + y);
}

//The Main function
int main() {

  std::cout << "Using MyNamespace::add() to add two types:\n";
  double x = 100.5, y = 200.5;
  std::cout << "Adding " << x << " and " << y << " to give " << MyNamespace::add(x, y) << std::endl;

  //Adding two different types, but type compatible with addition
  int a = 100;
  char c = 'A';
  std::cout << "Adding " << a << " and " << c << " to give " << MyNamespace::add(a, c) << std::endl;

  std::cout << "Using add(mul, x, y) to add two types:\n";
  std::cout << "Adding " << a << " and " << c << " to give " << add(10, a, c) << std::endl;
  return 0;
}

在此示例中,我正在使用现代C++实践。
其中一些基于标准模板库(STL)。
我还使用尾随返回类型,在声明函数原型之后,可以其中指定函数的返回类型。

输出

Using MyNamespace::add() to add two types:
Adding 100.5 and 200.5 to give 301
Adding 100 and A to give 165
Using add(mul, x, y) to add two types:
Adding 100 and A to give 1650

如您所见,我们确实可以在不同的作用域上编写两个不同的函数add()

现在,我们使用类转到另一个名称空间示例。

在命名空间中使用类

我们还可以在名称空间中使用类。
遵循相同的声明模式。

namespace MyNamespace {
  //We can have functions inside a namespace
  template <typename T, typename R>
      auto add(T x, R y) -> decltype(x + y) {
          return x + y;
      }
  //We can also have a Class inside a namespace
  class MyClass {
      public:
          int a;
          MyClass(int val=0) { a = val; }
          ~MyClass() { std::cout << "Destructor called for MyNamespace::MyClass\n"; }
  };
}

让我们编写驱动程序以利用新的名称空间成员!

#include <iostream>

//Example of a Namespace:
//This is used to manage function signatures so that they don't conflict
//Think of a namespace as a named scope binding various functions and classes
namespace MyNamespace {
  //We can have functions inside a namespace
  template <typename T, typename R>
      auto add(T x, R y) -> decltype(x + y) {
          return x + y;
      }
  //We can also have a Class inside a namespace
  class MyClass {
      public:
          int a;
          MyClass(int val=0) { a = val; }
          ~MyClass() { std::cout << "Destructor called for MyNamespace::MyClass\n"; }
  };
}

//The Main function
int main() {
  //Use MyClass from MyNamespace    MyNamespace::MyClass 
  my_obj(100);
  std::cout << "Created an object from MyNamespace::MyClass\n";
  std::cout << "my_obj.a = " << my_obj.a << std::endl;
  return 0;
}

输出

Created an object from MyNamespace::MyClass
my_obj.a = 100
Destructor called for MyNamespace::MyClass

我们还可以通过在名称空间之外定义Class,但使用范围解析运算符来重写示例。

namespace MyNamespace {
  //We can have functions inside a namespace
  template <typename T, typename R>
      auto add(T x, R y) -> decltype(x + y) {
          return x + y;
      }
  //We can also have a Class inside a namespace
  class MyClass {
      public:
          int a;
          MyClass(int val);
          ~MyClass();
  };
  //We can define methods of the class within the namespace, but outside the class
  MyClass::MyClass(int val = 0) {
      MyClass::a = val;
  }
}
//We can also define it outside the namespace!
MyNamespace::MyClass::~MyClass() {
 std::cout << "Destructor called for MyNamespace::MyClass\n";
}

直接在C++中访问名称空间的成员

如果名称空间依赖关系变得很长,则键入成员的全部范围来访问它可能很繁琐且耗时。
为了克服这个问题,C++引入了" using"指令。

这将使我们可以直接访问名称空间中的所有名称(成员)!

我们通常将此指令放在文件的顶部,以便它适用于文件中的所有位置。

要使用此语法,语法如下:

using namespace namespace_name;

其中namespace_name是您的命名空间名称。
就我而言,它是MyNamespace。
因此,此语句将变为:

using namespace MyNamespace;

现在,我们可以直接访问MyNamespace内部的成员!但是请记住,如果存在同名的全局变量,则编译器将引发错误。

#include <iostream>

//Example of a Namespace:
//This is used to manage function signatures so that they don't conflict
namespace MyNamespace {
  int my_data;
}

using namespace MyNamespace;

//The Main function
int main() {
  //Can now access directly, provided there is no global variable of the same name!
  my_data = 200;
  std::cout << "my_data is now :" << my_data << std::endl;
  return 0;
}

输出

my_data is now :200