不会有人看完这篇文章还不会C++的命名空间吧?不会吧?
Posted 做1个快乐的程序员
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不会有人看完这篇文章还不会C++的命名空间吧?不会吧?相关的知识,希望对你有一定的参考价值。
对于初学C++的小白来说,遇到的第一个代码应该就是下面的“hello world!”,看到这段代码会一头无水。不得不
提出十万个为什么?
为什么头文件的引用不是像C语言一样有**.h**?
为什么头文件下面会有**using namespace std**;?
为什么一行代码就能输出代码?
“hello world!”两边的**cout和end1**是什么?
....
#include <iostream>
using namespace std;
int main()
{
cout << "hello world!" << endl;
return 0;
}
这篇文章讲为你逐一解开疑惑,如果看完了还不懂来打小编。
1、命名空间
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,
可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace
关键字的出现就是针对这种问题的。
比如下面这段代码,我们定义了名为scanf、strlen的int类型的变量,但是我们知道,scafn和strlen是C语言库函数里面的两个函数,如果我的代码里想用这两个名称命名变量,直接定义输出是没有问题的,我们可以看到编译器正常编译并输出。
代码一:
int main()
{
int scanf = 10;
int strlen = 20;
printf("%d-%d\\n",scanf,strlen);
return 0;
}
但是如果我们在使用这两个名称变量的同时,调用库函数中同名的函数呢?会出现什么情况?
代码二:
int main()
{
int scanf = 10;
int strlen = 20;
scanf("%d",&scanf);
return 0;
}
编译器报错!!!!!
在理想状态下,我们希望的是第一个sacnf是调用库函数中的,第二个scanf是自己代码中的。但是编译器无法做到,编译器遵循的是***!就近原则!***,C编译器会就近的认为这两个sacnf都是我代码里的,以上代码中两个scanf和strlen定义在了main函数里的局部变量,那我们定义在全局变量会出现什么情况呢?
代码三:
int scanf = 10;
int strlen = 20;
int main()
{
printf("%d-%d\\n",scanf,strlen);
return 0;
}
这时候编译器报了重定义的错误!
这是为什么呢???
C语言的调用遵循就近原则,遇到一个函数或者变量他会先去离自己最近的局部寻找,如果找到就会调用,如果找不到就会去全局寻找。
如果定义在局部中,代码一的情况:编译器会默认去局部或者全局找变量,然后在main函数中找到了scanf和strlen,正常打印输出。代码二的情况:调用scanf函数,编译器同样会去局部找,然后找到了定义的scanf变量,然后这个是变量,并不是函数,不支持输入形参,所以报错。代码三的情况:将两个变量定义在了全局,编译器就近原则,直接去头文件中寻找,并在库函数里找到了scanf和strlen函数,所以报了重定义的错误!
这样解释大家就明白了三种情况是怎么编译通过和报错的了吧。
我们知道C++的产生是为了解决C不能解决的一些问题,弥补了C++中存在的一些问题,那么C++是怎么解决这种命名冲突的问题的呢?---------定义命名空间
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。
namespace命名空间实际上是一个域,本质是为了解决C语言命名冲突问题。把函数或者变量放到域里面去。
代码四:
我们使用namespace关键字+{}一对方括号,就把相应的变量和函数放到了对应的域中。
在下面的代码中,我们定义了xd域,在域中定义了sacnf、strlen变量以及Add函数,并且在xd域中又嵌套了N3域,
在N3域中也定义了变量c、d和Sub函数,这说明命名空间是可以嵌套使用的,并且可以一直嵌套!
我们使用“::”来访问指定域中的变量或函数,“::”称为域作用限定符,用来指定后面的变量、函数属于哪个域的。
namespace xd
{
int scanf = 10;
int strlen = 20;
int Add(int x, int y)
{
return x + y;
}
//命名空间可以嵌套 - 可以一直套
namespace N3
{
int c;
int d;
int Sub(int left, int right)
{
return left - right;
}
}
}
int main()
{
//指定访问xd命名空间中的
//::域作用限定符,指定后面的变量是属于那个域的
printf("%x\\n", xd::scanf);
printf("%x\\n", xd::strlen);
xd::Add(2, 3);
xd::N3::Sub(8, 7);
return 0;
}
注意:
a:同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
b:即在同一个工程其他.c文件中,还可以再定义一个N1、xd域。
c:但是在不同.c文件中定义相同名称的命名空间,但是命名空间中的变量、函数的名称不能相同。
2、解释hello world代码
#include <iostream>
using namespace std;
int main()
{
cout << "hello world!" << endl;
return 0;
}
回归最初的代码,小编为大家解释你们的疑惑。
问题一:为什么C++代码的头文件引用没有.h
答:#include <iostream.h> //老一点的C++标准用这个,比如:VC6.0,带.h头文件的是没有std命名空间的。新的C++没有.h,是为了和老的C++版本区分。
问题二:C++引用头文件下面的using namespace std;
答:C++库为了防止命名冲突,把自己库即标准库里面的东西都定义在一个std的命名空间中。所以要使用标准库中的东西有三种方式:
a:指定命名空间 - std::cout << “hello world!” << std::endl;
–这种方法比较麻烦,每个地方要用都要指定,但是他是最规范的使用方式。
b:把std整个展开 - using namespace std;
–相当于库里面的东西都到全局域了,看起来方便了,但如果我们自己定义的东西跟库冲突了,就没办法解决了 - 一夜回到解放前,就跟C之前一样了,C++做的就白费了
–所以规范的工程项目中是不推荐这种方式的。日常练习是可以的。
c:对部分常用的库里面的东西展开 - using std::cout; using std::end1;
–针对1和2折中的方式,项目中也会经常用。
#include <iostream>
#include <vector>
#include <string>
//b方式
using namespace std;
//c方式
using std::cout;
using std::endl;
int main()
{
//a方式
std::cout << "hello world!" << std::endl;
std::vector<int> v;
std::string s;
//b方式
cout << "hello world!" << endl;
vector<int> v1;
string s2;
//c方式
cout << "hello world!" << endl;
vector<int> v3;
string s3;
return 0;
}
问题三:cout和end1是什么?
答:cout严格来说是一个类对象,是ostream类型的全局对象 - cout
istream类型的全局对象cin
end1全局的换行符号
int main()
{
//"hello world!"这是一个字符串,他要流向前面的cout对象中去,这个对象就是控制台
std::cout << "hello world!";
//后面的是换行的意思,end1换行符号
std::cout << "hello world!" << std::endl << std::endl;
//对比C语言,printf和scanf,cout和cin的区别是什么?
//cout和cin可以做到自动识别类型!!
int a = 10;
int* p = &a;
printf("%d,%p\\n", a, p);//C语言
std::cout << a << "," << p << std::endl;//C++
return 0;
}
本篇文章到这就结束了哦,不知道大家有没有看懂,没有看懂私聊小编,说下你的疑问,小编会耐心给你解答滴。动动你可爱的小手手,给小编个鼓励。
以上是关于不会有人看完这篇文章还不会C++的命名空间吧?不会吧?的主要内容,如果未能解决你的问题,请参考以下文章