c++ ------命名空间
前言
**
好久不见,甚是想念~今天我们讲解的是关于c++命名空间的一些知识点,这只是开胃小菜哦,期待我们后面更深入知识的灵魂碰撞吧
**
一.命名空间
怎么形容呢~命名空间出现的情况有两种:
第一种就是自命名的变量与封存在std库函数命名冲突了。(std相当于是c++标准库里包含了c++所有的函数与对象名,std本身也是命名空间)
第二种就是自命名变量互相冲突了。这种发生场景很常见,无论是与别人对接工作又或是参照对方源代码都会出现这种情况。
cpp
#include <stdio.h>
#include <stdlib.h>
//命名变量与库里的函数名冲突
int rand = 0;
int main()
{
printf("%d\n", rand);
return 0;
}
在C语言中是无法解决该问题的,所以这也使得在C++改进此问题。
怎么说呢~就比如有一个人偶叫壮壮,它是早在洪荒之初(std库)就被定义的。后来呢又出现了一个人偶也叫壮壮,只不过这个人偶是我们人工捏造的(自命名变量)。那就导致命名冲突了,因为编译器看着两个壮壮不知道到底要用哪个。在它的视野里两人都叫壮壮,没有区分。
cpp
#include <stdio.h>
#include <stdlib.h>
namespace lj
{
int rand = 0;
}
int main()
{
//::域作用限定符
printf("%d\n", lj::rand);
return 0;
}
而命名空间要做的就是把其中一个人偶关在一个房间里,让外面的那个使系统默认只能看到它,那么系统就会默认使用它。那么关在房间里的呢需要一把钥匙,只有找到钥匙才可以让系统看到被关在里面的它并使用它。(而lj::就是我们所在命名空间的钥匙)
有了命名空间可以很好地解决上述两种情况。
命名空间的进一步拓展
cpp
namespace lj
{
int rand = 0;
int Add(int x, int y)
{
return x + y;
}
}
int main()
{
printf("%d\n", lj::rand);
lj::Add(1, 2);
return 0;
}
命名空间也同样可以对函数使用,不过得注意若想用自己写的函数需要一把钥匙(lj::)。
cpp
namespace lj
{
int rand = 0;
int Add(int x, int y)
{
return x + y;
}
struct Node
{
struct Node* node;
int val;
};
}
int main()
{
printf("%d\n", lj::rand);
lj::Add(1, 2);
//用结构体定义一个节点
struct lj::Node node;
return 0;
}
命名空间对结构体同样适用,需要注意的是lj::是要放到命名变量的前面,不能放到struct前面。
cpp
namespace lj
{
namespace lj1
{
int rand = 0;
}
namespace lj2
{
int rand = 1;
}
int Add(int x, int y)
{
return x + y;
}
struct Node
{
struct Node* node;
int val;
};
}
int main()
{
printf("%d\n", lj::lj1::rand);
printf("%d\n", lj::lj2::rand);
lj::Add(1, 2);
//用结构体定义一个节点
struct lj::Node node;
return 0;
}
命名空间还有一个特性,当有多个命名相同的变量时命名空间可以嵌套。(虽然感觉日常不会用到)
**
还有一个小知识点,举例我们在和对接工作时都用到了自己写的栈函数,但我们又不想去用他的,如何避免这种情况发生呢?我们可以用命名空间把所声明的栈与定义的栈都包含起来,后面在用的时候用这把钥匙开门就能找到我们所写的栈了。不用担心2个命名空间相同,因为在.h与.cpp分别有相同的命名空间时,最后相同命名空间会汇总在一起的。
**
不过有了命名空间感觉好麻烦,为了能够避免命名冲突我们需要在每一次通过钥匙才能用到我们想要的变量,虽然这样很安全,但是在测试时还是很不方便的,毕竟我们是自己测试,不用与其他人对接。
cpp
using namespace lj;
int main()
{
//lj::ST s;
ST s;
StackInit(&s);
StackPush(&s, 1);
StackPush(&s, 2);
StackPush(&s, 3);
StackPush(&s, 4);
return 0;
}
我们需要有一种可以改变编译器默认选择的方法,使得每次运行的时候都默认优先选择我们所在的命名空间的变量,而非std库里面默认定义的变量。usingnamespace lj------解放命名空间。
*那么在这里我们就可以理解using namespace std的用途了,它是C++官方库定义的命名空间,也因此作为编译器默认选择的对象(说是默认,其实只不过是变为全局变量),这样库里的东西就随便用了。
不过命名空间还是不要随随便便展开,std之所以封起来就是防止我们所命名的变量与库里冲突。
*总结起来就是收纳盒理论,平时封装好的函数都存在std收纳盒中,当我们要使用它时就得把收纳盒的东西倒出来这样才可以找到,因为在收纳盒的掩盖下我们的全局视野里是不会看到那个我们需要用的对象的。
二.io流特性
就像我们一开始学习c语言的输入(scanf)与输出(printf)一样,在开启c++的学习之前我们也要认识属于c++的输入与输出。当然c++能够兼容99%的c语言特性,我们可以视情况灵活运用。
在使用io流特性之前需要引入头文件:#include
不过cout与cin封存在std里在全局变量是默认找不到的,所以我们需要using namespace std或者std::cout指定使用。
流插入我们可以理解为从外部发出电波给到b,而流提取就是从b里面提取数据并打印出来。
相较于c语言的优点就是在输入输出的时候不用去在意变量的类型,什么%d,%lf等等通通不用管。它会自动去识别变量类型。
当然也有不足之处,在我们需要控制浮点数精度时反而很麻烦,这时候倒不如直接用printf来得简单。
除此之外,换行的方式也具有多种。
有一个问题,每次指定命名空间很麻烦,展开又危险。这就引申出命名空间的第三种用途:指定命名展开。
cpp
using std::cout;
using std::endl;
int main()
{
cout << "hello world\n";
cout << "hello world"<<"\n";
cout << "hello world" << endl;
return 0;
}