目录
命名冲突
#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时会优先采用局部域的值,即局部域优先原则
#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;
}
缺点:
-
潜在命名冲突(重点):如果多个命名空间中有相同名称的标识符(如变量、函数等),使用
using namespace
可能会导致名称冲突 -
可读性降低:用户无法轻易知道特定标识符是来自哪个命名空间
-
潜在影响全局范围:如果将所有内容都引入当前作用域,可能会意外地影响全局范围内其他部分或第三方库中的同名标识符(rand函数的例子)
-
编译时间增加:当涉及大型项目时,编译时需要处理大量额外的符号会导致编译时间增加
对于std库在平时练习时可以完全展开,因为其中的cout和cin等函数会经常使用,如果不是练习还是建议在使用的时候展开或者提前将要用到的部分函数展开:
//方法一
#include <iostream>
using namespace std;
int main()
{
int i = 0;
std::cin >> i;
cout << "xxxx" << endl;
cout << "xxxx" << endl;
return 0;
}
//方法二
#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),包括了处理输入和输出数据流的类和函数。例如
cin
,cout
,cerr
,clog
等都属于 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 命名空间::内容名的形式获得相应的权限
c++的关键字
~over~