备注①:name:符号。指的实体包括:变量、函数、类

备注②:认为全局命名空间也是一个包,在此称作 ROOT:: 或 global::

(这样就有了两个特别的包:一个是全局包,一个是std包。但对于编译器(pack-path. names模型)来说,它们和用户自定义的namespace没有区别)


修正1. global::(全局包)中的names,并不都是用户自定义的。

2.   两条重要认识,以及由此解释一些之前的问题

一、using namespace xxx; <—> using pack-A的本质作用:   相当于把 导入的Pack-A的 names 移到 using pack-A;  这行文字所在的那个namespace   的names空间里。

二、所有非ROOT 的namespace里 ,都已默认存在 using namespace ::  (移入了ROOT包的 names ) ——>  所以才直接用全局的names

结论1:之前都是 "using namespace std "写在自定义namespace外,那么这行处在global::中,导致:把引进来的std::包里的names移到了 global包,成为全局的名字。

又因为各namespace已默认导入了global::names,所以这部分std::names进入了各namespace里。

导致的问题: 这样,当在wjh::内写某个name的定义时,若未加namespace-xxx::前缀而直接引用了 ‘fuck’,那么这个fuck可能有3处来源:

①wjh::fuck

②(global::) fuck

③namespace-ABC::fuck    //     在全局(=namespace外部) 中using namespace ABC后, ABC::下的names进入全局空间,进一步进入wjh::

只要以上3个namespace里存在不止一个 fuck 这个name,就属于 ‘Ambiguous function call’ 报错。 (也可能不报错,但编译器会自己挑一个合适的用!)

不存在什么优先认定,3个中只能存在1个!

     /*

*    ↑   修正:实验了一下,当不加包路径的 fuck存在上面①②③时,确实会选择①、编译器不提示报错。 所以同namespace的那个name确实是优先的

*         但当同namespace下无此name,②③是会冲突的。

*/

结论2:所以using namespace std; 为什么不能使用?

别人的模块引用了你的这个头文件后,多了这行字,原来未加namespace:: 引用的name只有一处定义,现在可能就多了个定义,

而编译器又不报错,就导致‘God knows what’种种奇特行为(因为引用的name被偷偷替换掉了)


写段实验代码验证一下以上认识:

   前提:<test.h> :  定义一个global::fuckit();    在namespace wjh{ }里也定义一个fuckit(); 

观察:此时在wjh{ } 中引用 fuckit()  (不加wjh::),看是否提示


#ifndef _TRIAL_1_H
#define _TRIAL_1_H

int fuckit();

namespace wjh {
   int fuckit();
}
#endif


在global::下使用如下 (该main位于global空间)

(using namespace wjh;  把 wjh::fuckit 这个name移入了global::中)

#include "trial-1.h"

using namespace wjh;

int main() {
::fuckit();
wjh::fuckit();
fuckit(); //报错! system("pause");
return ;
}

截图如下:


更进一步的实验:

 #ifndef _TRIAL_1_H
#define _TRIAL_1_H // ③ s_t_d::fuckit
namespace s_t_d {
int fuckit();
} // ② (global::) fuckit
int fuckit(); // ① wjh::fuckit
namespace wjh {
using namespace s_t_d;
int fuckit();
void call_fuckit();
} #endif
 #include "trial-1.h"

 #include <iostream>
#include <cstdlib> //using namespace s_t_d;
//using namespace wjh; int s_t_d::fuckit() {
std::cout << "s_t_d:: fuckit" << std::endl;
return ;
}
int fuckit() {
std::cout << "global:: fuckit" << std::endl;
return ;
}
int wjh::fuckit() {
std::cout << "wjh:: fuckit" << std::endl;
return ;
} void wjh::call_fuckit() {
using namespace s_t_d;
std::cout << "running in wjh:: calling fuckit ..." << std::endl;
fuckit();
} int main() {
wjh::call_fuckit(); fuckit(); system("pause");
return ;
}

经实验验证,修正对using namespace std的认识的更多相关文章

  1. using namespace std 和 using std::cin

    相较using std::cin使用using namespace std不会使得程序的效率变低,或者稳定性降低,只是这样作会将很多的名字引入程序,使得程序员使用的名字集合变小,容易引起命名冲突. 在 ...

  2. namespace std

    c++中使用namespace来防止命名冲突(重命名),我们经常使用的一些函数和变量都被放在一个叫std的namespace中,如标准I/O流操作,vector等等.我们在每一个文件中都可使用std中 ...

  3. C++ using namespace std(转载)

    转载自http://www.kuqin.com/language/20080107/3532.html 感谢这位大神的解答! 以下的内容摘抄自转载的文章里面的部分内容. 早些的实现将标准库功能定义在全 ...

  4. 不要在头文件中使用 using namespace std;

    不要在头文件中使用(using namespace std;).   若你使用了using namespace std;,在某一头文件中,那么包含这些头文件的文件就失去了"namespace ...

  5. using namespace std

    using namespace std std 是一个命名空间..不同的命名空间可以有相同的类名被定义 ..using namespace std;就是指明下面的程序使用std,如果不用这句指明的话就 ...

  6. #include<iostream.h>与#include<iostream> using namespace std的区别

    所谓namespace,是指标识符的各种可见范围.C++标准程序库中的所有标识符都被定义于一个名为std的namespace中.  一 :<iostream>和<iostream.h ...

  7. 关于using namespace std

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~关于using   namespace   std ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ...

  8. 实验验证sys和system用户全库导出的区别

    我们在做逻辑数据泵全库导出的时候,有两种流行的写法,一种是sys用户导出,一种是使用system用户导出. 现在想知道二者之间有什么区别?实验验证之前不妨先思考一下: sys和system用户的权限区 ...

  9. 有多个.h引用时,不能有using namespace std

    #include<iostream.h> #include<math.h> //using namespace std; 有多个.h引用时,不能有这个,否则无法运行. void ...

随机推荐

  1. mysql数据库之主从复制+双主--MMM

    mysql复制:在主数据库中,前端用户每执行一个写操作/语句,都会在二进制日志中保存一个事件,把这个事件从mysql的服务器中3306端口发送给从服务器,从服务器把这个事件接受下来,接受下来先保存在本 ...

  2. java lambda表达式检查list集合是否存在某个值

    import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class ...

  3. 《Pro Continuous Delivery With Jenkins 2.0》随书笔记

    今天同时看完<Pro Continuous Delivery With Jenkins 2.0>, 这书与工作关系很大,但也是快速翻翻. 本书着重点jenkins高可用环境搭建,与gith ...

  4. python操作mysql(增、删、改、查)

    用python操作数据库,特别是做性能测试造存量数据时特别简单方便,比存储过程方便多了. 连接数据库 前提:安装mysql.python,参考:https://www.cnblogs.com/Uncl ...

  5. 【oracle】drop,truncate,delete用法

    drop: drop table 表名:删表 truncate: truncate table 表名:清空数据 delete: delete table 表名 [where 条件]:删某数据 日志:d ...

  6. 【Linux】查看端口和进程

    netstat -tunlp ps -ef|grep process_name

  7. RabbitMQ六种队列模式-工作队列模式

    前言 RabbitMQ六种队列模式-简单队列RabbitMQ六种队列模式-工作队列 [本文]RabbitMQ六种队列模式-发布订阅RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主 ...

  8. 第05组 Beta冲刺(1/4)

    第05组 Beta冲刺(1/4) 队名:天码行空 组长博客连接 作业博客连接 团队燃尽图(共享): GitHub当日代码/文档签入记录展示(共享): 组员情况: 组员1:卢欢(组长) 过去两天完成了哪 ...

  9. 前端/H5/JS:通过URL下载文件并转存到其他服务器(微信),Blob文件转File文件

    现在有一个图片URL,在自己服务器上,一个微信提供的媒体文件上传URL,我在前端通过JS实现转存微信服务器 1. http://file.xxx.com/asd.jpg 自己的 2.https://a ...

  10. 5-STM32物联网开发WIFI(ESP8266)+GPRS(Air202)系统方案安全篇(配置MQTT的SSL证书,验证安全通信)

    4-STM32物联网开发WIFI(ESP8266)+GPRS(Air202)系统方案安全篇(为域名申请SSl证书) 前面的准备工作终于完了 复制这两个证书 放到云端MQTT的这个位置,其实放哪里都可以 ...