自学内容网 自学内容网

C++的命名空间

目录

命名冲突

域作用限定符::

命名空间域 

命名空间的定义

小补充(一)

命名空间的使用

 iostream与std的关系

小补充(二)

 c++的关键字


命名冲突

运行下面两端代码:

#include <stdio.h>
int rand = 10;

int main()
{
printf("hello world\n");
printf("%d\n", rand);
return 0;
}
#include <stdio.h>
#include <stdlib.h>  //新增包含头文件

int rand = 10;

int main()
{
printf("hello world\n");
printf("%d\n", rand);
return 0;
}

我们会发现不包含stdlib头文件之前的代码可以正常执行,包含了stdlib头文件的代码会报错:

        这是因为rand是stdlib头文件中一个被定义的函数,而int rand是对rand函数的重定义,因此可以得到这样的结论:c语言的全局变量会出现命名冲突的问题。

        命名冲突发生的对象一般是程序员与库(标准库或第三方库)、程序员与程序员之间(项目中二人起了相同的变量或函数名)

        c/c++中有域的概念,①处的x属于全局域,②处的x属于局部域,当我们使用变量x时会优先采用局部域的值,即局部域优先原则(因此执行下面代码的结果为1)

#include <stdio.h>

①int x = 0;//全局域

int main()
{
    ②int x = 1;//局部域
printf("hello world\n");
printf("%d\n", x);
return 0;
}

域作用限定符::

作用:自主选择要使用哪个域中的变量

使用方式:域名::变量名

c++主要有全局域、局部域、命名空间域、类域的概念

注意事项:

1、域名为空时默认为全局域

2、读取局部域时一般不使用该符号,因为局部域优先原则,读取时肯定先读局部域

#include <stdio.h>

int x = 0;

int main()
{
    int x = 1;
printf("hello world\n");
printf("%d\n", ::x);
return 0;
}

命名空间域 

作用:实现重名变量的共存(解决命名冲突)

命名空间的定义

格式:namespace 命名空间域名 {变量名} 

1、只能定义在全局

#include <stdio.h>
namespace bit1
{
    int x = 0;
}

namespace bit2
{
    int x = 1;
}

int main()
{
printf("%d\n", x);
printf("%d\n", x);
return 0;
}

运行上述代码后仍然报错,这是因为编译器在编译时会按如下顺序对变量进行搜索:

①当前局部域

②全局域

③指定的命名空间域

#include <stdio.h>
namespace bit1
{
    int x = 0;
}

namespace bit2
{
    int x = 1;
}

int main()
{
printf("%d\n", bit1::x);
printf("%d\n", bit2::x);
return 0;
}

至此,我们在刚开始产生的rand函数问题也可以得到解决:

#include <stdio.h>
#include <stdlib.h>
namespace bit1
{
int x = 0;
int rand = 10;
}

namespace bit2
{
int x = 1;
}

int main()
{
printf("%d\n", bit1::x);
printf("%d\n", bit2::x);
printf("%d\n", bit1::rand);
return 0;
}


2、命名空间域中可以定义变量/函数/类型

namespace bit1
{
int x = 10;

int Add(int left, int right)
{
return left + right;
}

struct Node
{
struct Node* next;
int val;
};
}


3、 同一项目中允许存在多个相同名称的命名空间,编译器最后会将它们合并

//test.h头文件
namespace N1
{
int Mul(int left, int right)
 {
     return left * right;
 }
}

//TEST.h头文件
namespace N1
{
    int rand = 10;
}

//合并后
namespace N1
{
    int Mul(int left, int right)
     {
         return left * right;
     }
    
     int rand = 10;
}


4、命名空间域可以嵌套

namespace N1
{
int a;
int b;
int Add(int left, int right)
 {
     return left + right;
 }
    namespace N2
     {
         int c;
         int d;
         int Sub(int left, int right)
         {
             return left - right;
         }
     }
}

小补充(一)

        在未指定命名空间域前,报错的内容是x未定义而不是重定义,这就证明被命名空间域包括的变量虽然是全局变量(仍然可以整个程序被访问)但是不处于全局域中,以下是三种域对变量的影响:

域名是否对声明周期产生影响是否对变量的访问产生影响
全局域
局部域
命名空间域

命名空间的使用

1、不使用using的指定访问

特点:用哪个声明哪个(命名空间::内容名)

#include <iostream>
namespace N
{
int a = 10;

int Add(int left, int right)
{
return left + right;
}

struct Node
{
struct Node* next;
int val;
};
}

int main()
{
    printf("%d\n", N::a);
    return 0;    
}

2、使用using的指定访问

特点:提前打招呼,下次再用就不需要声明 (using 命名空间::内容名)

#include <iostream>
namespace N
{
int a = 10;
    int b = 20;
 
int Add(int left, int right)
{
return left + right;
}

struct Node
{
struct Node* next;
int val;
};
}

using N::b;
int main()
{
    printf("%d\n", N::a);
    printf("%d\n", b);
    return 0;    
}

3、命名空间的全部展开

特点: 将整个命名空间中的内容全部可以直接访问

#include <iostream>
namespace N
{
int a = 10;
int b = 20;

int Add(int left, int right)
{
return left + right;
}

struct Node
{
struct Node* next;
int val;
};
}

using namespace N;
int main()
{
printf("%d\n", a);
printf("%d\n", b);
printf("%d\n", Add(10, 20));
return 0;
}

缺点: 

  1. 潜在命名冲突(重点)如果多个命名空间中有相同名称的标识符(如变量、函数等),使用 using namespace 可能会导致名称冲突。这会使代码难以理解和维护。

  2. 可读性降低展开整个命名空间可能使代码更加难以阅读,因为读者无法轻易知道特定标识符是来自哪个命名空间。

  3. 潜在影响全局范围如果将所有内容都引入当前作用域,可能会意外地影响全局范围内其他部分或第三方库中的同名标识符。

  4. 编译时间增加当涉及到大型项目时,在编译时需要处理大量额外的符号可能导致编译时间增加。

        尽管完全展开命名空间存在命名冲突的缺点,但是有一些命名空间中的内容是我们常用的,我们可以采用指定访问的方法访问常用的内容:

//方法一
#include <iostream>

using std::cout;
using std::endl;

int main()
{
int i = 0;
std::cin >> i;
cout << "xxxx" << endl;
cout << "xxxx" << endl;
return 0;
}

//方法二
#include <iostream>

int main()
{
int i = 0;
std::cin >> i;
std::cout << "xxxx" << std::endl;
std::cout << "xxxx" << std::endl;
return 0;
}

 iostream与std的关系

  • iostream:指的是输入输出流(input/output stream),包括了处理输入和输出数据流的类和函数。例如 cincoutcerrclog 等都属于 iostream 库中定义的对象。

  • std:代表 C++ 标准库中定义的所有内容所在命名空间。C++ 标准库提供了广泛且功能强大的类、函数和算法,在编写 C++ 程序时经常会用到这些标准库中提供的元素。

 io包含了与 I/O 相关联的部分内容(学生名单),而内容位于 std 命名空间内(特定学生)


5、可以将同一个函数放在不同的命名空间中使用 

#include <iostream>
namespace N
{
int Add(int left, int right)
{
return left + right;
}
}

namespace M
{
int Add(int left, int right)
{
return left + right;
}
}

using namespace N;
int main()
{

printf("%d\n",N::Add(10, 20));
printf("%d\n",M::Add(10, 20));
return 0;
}

6、可将同一命名空间中的两个相同函数再放入两个不同的命名空间中(命名空间的嵌套) 

#include <iostream>
namespace N
{
namespace a
{
int Add(int left, int right)
{
return left + right;
}
}
namespace b
{
int Add(int left, int right)
{
return left + right;
}
}
}

using namespace N;
int main()
{

printf("%d\n",N::a::Add(10, 20));  //注意这里的调用方式!!
printf("%d\n",N::b::Add(10, 20));  //注意这里的调用方式!!
return 0;
}

小补充(二)

        命名空间域就相当于一个被设置了访问权限的文件,一般情况下我们在使用命名空间域中的内容时的形式是命名空间域::内容名,如果我们想直接用命名空间中的内容就会报错。而using的作用就相当于在使用之前打开该“文件”的全部或某个内容的权限,即在使用前以using 命名空间::内容名的形式获得相应的权限:

#include <iostream>
namespace N
{
int a = 10;
    int b = 20;
 
int Add(int left, int right)
{
return left + right;
}

struct Node
{
struct Node* next;
int val;
};
}

using N::b;
int main()
{
    printf("%d\n", N::a);
    printf("%d\n", b);
    return 0;    
}

 c++的关键字

~over~


原文地址:https://blog.csdn.net/m0_73975164/article/details/136264568

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!