精华内容
下载资源
问答
  • 文章目录C++学习04-命名冲突命名空间命名冲突命名空间全局命名空间标准命名空间命名空间标识符的使用显式命名空间限定符std::直接使用命名空间 using namespace std小结 C++学习04-命名冲突命名空间 命名冲突 举...

    C++学习04-命名冲突和命名空间

    命名冲突

    举一个小例子

    ​ 假设您是第一次开车去朋友家,给您的地址是 Mill City 的 245 Front Street。到达米尔城后,您拿出地图,却发现米尔城实际上有两条不同的前街,彼此隔着城镇!你会去哪一个?除非有其他线索可以帮助您做出决定(例如,您记得他的房子在河边),否则您必须打电话给您的朋友并询问更多信息。因为这会令人困惑且效率低下(尤其是对于您的邮递员),所以在大多数国家/地区,城市内的所有街道名称和房屋地址都必须是唯一的。

    ​ 类似地,C++ 要求所有标识符都没有歧义。如果以编译器或链接器无法区分的方式将两个相同的标识符引入同一个程序,编译器或链接器将产生错误。此错误通常称为命名冲突(或命名冲突)。

    上段例子引用自cpp-tutorial-2.8

    下面再举一个实际函数中的例子

    a.cpp

    #include <iostream>
    void myFcn(int x)
    {
        std::cout << x;
    }
    

    main.cpp

    #include <iostream>
    void myFcn(int x)
    {
        std::cout << 2 * x;
    }
    int main()
    {
        return 0;
    }
    

    ​ 编译器在编译该项目时,会独立的编译项目下的所有文件,所以两个cpp文件编译都没有问题

    ​ 但是当链接器执行时,它会将a.cpp和main.cpp的所有定义链接在一起,此时就会发现函数myfunc的冲突定义,于是程序立即因为错误而终止

    大多数命名冲突发生在两种情况下:

    1. 一个函数(或全局变量)的两个(或多个)定义被引入到编译成同一个程序的单独文件中。这将导致链接器错误,如上所示。
    2. 一个函数(或全局变量)的两个(或多个)定义被引入到同一个文件中(通常通过#include)。这将导致编译器错误。

    ​ 随着程序变大并使用更多标识符,引入命名冲突的几率显着增加。好消息是 C++ 提供了大量的机制来避免命名冲突。局部作用域,防止在函数内部定义的局部变量相互冲突,就是这样一种机制。但是局部作用域不适用于函数名称。那么我们如何避免函数名相互冲突呢?

    这就引出了命名空间的概念啦~


    命名空间

    ​ 如果您必须将邮件投递到两个地址,一个地址是 Mill City 的 Front Street 209,另一个地址是 Jonesville 的 Front Street 417,那么您将不会混淆该去哪里。换句话说,城市提供了分组,使我们能够消除可能相互冲突的地址的歧义。在这个类比中,命名空间就像城市一样。

    命名空间:命名空间就是一个为了消除歧义而声明的局部作用域,在一个命名空间内声明的任何名称都不会被误认为是其他作用域中的名称

    命名空间的用途

    ​ 命名空间通常用于对大型项目中的相关标识符进行分组,以帮助确保它们不会无意中与其他标识符发生冲突。例如,如果您将所有数学函数放在名为math的命名空间中,那么您的数学函数将不会与math命名空间之外的同名函数发生冲突。

    全局命名空间

    ​ 在 C++ 中,任何未在类、函数或命名空间中定义的名称都被视为隐式定义的命名空间的一部分,称为全局命名空间(有时也称为全局作用域)。

    ​ 在上面的示例中,函数 main() 和 myFcn() 的两个版本都在全局命名空间中定义。示例中遇到的命名冲突是因为 myFcn() 的两个版本最终都在全局命名空间内,这违反了命名空间中所有名称必须唯一的规则。

    标准命名空间

    我们以c++的cout输出标识符为例,深入理解命名空间的含义

    以下内容均转载自网址

    ​ 在最初设计 C++ 时,C++ 标准库中的所有标识符(包括 std::cin 和 std::cout)都可以在没有std:: 的情况下使用前缀(它们是全局命名空间的一部分)。但是,这意味着标准库中的任何标识符都可能与您为自己的标识符选择的任何名称(也在全局命名空间中定义)发生潜在冲突。当您#include标准库中的新文件时,正在运行的代码可能会突然发生命名冲突。或者更糟的是,在一个 C++ 版本下编译的程序可能无法在 C++ 的未来版本下编译,因为引入标准库的新标识符可能与已经编写的代码存在命名冲突。因此,C++ 将标准库中的所有功能都移到了名为**“std”(standard 的缩写)的命名空间**中。

    那么我们应该如何使用命名空间的标识符呢?


    命名空间标识符的使用

    以c++中的cout基本输出函数为例

    显式命名空间限定符std::

    当我们说std::cout 时,我们说的是“存在于命名空间std 中cout ”。

    #include <iostream>
    
    int main()
    {
        std::cout << "Hello world!"; // when we say cout, we mean the cout defined in the std namespace
        return 0;
    }
    
    • 这是使用cout最安全的方法,因为对于我们所引用的coutstd命名空间中的那个*cout)*没有歧义。

    直接使用命名空间 using namespace std

    ​ 直接引用了整个命名空间,此时当编译器区确定一个标识符cout究竟是什么时,它会在本地和std空间同时进行检索

    ​ 很多教程都推荐这种方法,因为它非常方便快捷,但是这种方法的使用却违背了命名空间的初衷,因为命名空间本地任然会对同一个cout产生冲突

    #include <iostream>
    
    using namespace std; // this is a using directive telling the compiler to check the std namespace when resolving identifiers with no prefix
    
    int main()
    {
        cout << "Hello world!"; // cout has no prefix, so the compiler will check to see if cout is defined locally or in namespace std
        return 0;
    }
    

    冲突

    #include <iostream> // imports the declaration of std::cout
    
    using namespace std; // makes std::cout accessible as "cout"
    
    int cout() // declares our own "cout" function
    {
        return 5;
    }
    
    int main()
    {
        cout << "Hello, world!"; // Compile error!  Which cout do we want here?  The one in the std namespace or the one we defined above?
    
        return 0;
    }
    

    ​ 上面的程序无法编译,因为编译器现在无法判断我们是想要我们定义的cout函数,还是在std命名空间内定义的cout。 当以这种方式使用 using 指令时,我们定义的任何标识符都可能与std命名空间中的任何同名标识符冲突。更糟糕的是,虽然今天的标识符名称可能不会发生冲突,但它可能会与未来语言修订版中添加到 std 命名空间的新标识符发生冲突,也就是说,同一个程序,在不同版本下的gcc标准可能不能运行,这是工程角度而言应该极力避免的东西,因为bug太难找了!这就是首先将标准库中的所有标识符移动到std命名空间的重点!

    小结

    ​ 避免在程序顶部或头文件中使用指令(例如using namespace std;)。它们违反了当初添加名称空间的初衷。

    ​ 但是在现在的打基础过程中,使用以下是可以的,但是到了真正的工程以及项目实践时,这种情况是完全不可取的!!!

    展开全文
  • 本篇文章我将向大家介绍C++中一个非常重要的语法,命名空间的概念。 首先一开始我想先请大家一段C语言代码: #include <stdio.h> int scanf = 0; int main() { printf("%d\n", scanf); } 很简单的一段代码...

    本篇文章我将向大家介绍C++中一个非常重要的语法,命名空间的概念。

    首先一开始我想先请大家一段C语言代码:

    #include <stdio.h>
    
    int scanf = 0;
    
    int main()
    {
    	printf("%d\n", scanf);
    }
    

    很简单的一段代码,这里我问一个最简单的问题,我的这段代码有没有错?

    这个时候可能有人觉得,必然是错的,scanf是C语言的一个标准输出函数啊,你怎么能用函数名来当变量呢?

    我要告诉大家的是,C语言中共有32个关键字,而C语言语法中只是规定不能用关键字来命名变量,但是并没有规定不能用函数名来命名。也就是说我用scanf来做变量名从语法角度出发是没有任何问题的,不过我想说的是,这段代码确实是有问题的,下面我们就来编译一下这段代码:
    在这里插入图片描述
    可以看到,提示的错误信息是scanf被重定义了,下面我来解释原因。

    我想大家C语言阶段都曾学到过,生成一个可执行程序需要预处理,编译,汇编,链接四个过程。而预处理阶段会将头文件里包含的所有函数都展开,而scanf是<stdio.h>这个头文件里包含的一个函数,也就意味着这个函数在预处理之后会被展开到当前代码中。

    这样当你在main函数中打印scanf的时候就会出现问题了,你要打印的scanf究竟是库函数中的函数名,还是你主动创建的全局变量,这就会产生歧义,从而导致错误。

    这就是C语言语法中一些不严谨的地方。这里可能有人要说了,这有什么,那我定义变量名的时候小心一点,尽量不和库函数名发生冲突不就好了。

    这里我来为大家举一个例子,假设你现在是一名公司的员工,你们组一共是十个人,现在正在共同完成一个项目。实现一个大项目,肯定是需要协作进行的,你的组长现在把这个项目分为好几个模块,然后你们每个人负责一部分。当你和你的组员都完成之后,再把这些模块汇总成完整的项目。

    现在你有一个同事张三,你在你所负责模块的时候创建了一个变量length,而张三又在它的模块里创建了一个同样命名为length的变量。你们两个创建的变量作用肯定是不同的,但是变量名却一样,这样最后在汇总的时候项目中是不是就会出现两个名为length的变量,从而导致变量的重定义。

    我举这个例子的目的是为了告诉大家,有时候用C语言写代码的时候是难以解决命名冲突的问题的,而C++中为了解决这个问题就提出了命名空间的概念。

    下面我们就来看命名空间是一个怎样的东西。


    1. 命名空间的概念

    在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染namespace关键字的出现就是针对这种问题的

    2. 命名空间的定义

    定义命名空间,需要使用到namespace 关键字,这个关键字的作用就是定义一个命名空间。namespace后面跟 命名空间的名字 ,这个名字就跟变量名一样可以随便取,然后 接一对{} 即可,{}中即为命名空间的成员。

    现在我们就来对上面的错误代码进行修正:

    #include <stdio.h>
    
    namespace ret 
    {
    	int scanf = 0;
    }
    
    int main()
    {	
    	printf("%d\n", scanf);
    }
    

    上述代码中我将定义的名scanf的全局变量封装在了名为ret的命名空间中了,命名空间就相当于C++中一块被隔离起来的空间,只要你不将它打开,里面的东西就不会出来。下面我们再来运行一下这段代码:
    在这里插入图片描述
    可以看到这次并未发生命名冲突,成功的打印出了一个值到屏幕上。这是因为命名空间的存在将我们原本定义的全局变量scanf给封装了起来,只要不打开,外界就不会接收到这个变量。因此代码中只有标准输入函数scanf,最终打印的结果是将该函数的地址以十进制的形式打印到了屏幕上。

    好,到这里我们算是初步的认识了一下命名空间是如何定义的,以及它的作用。接下来的问题是,你把变量封装在命名空间中,总得取出来用吧,关起来不用,那你还定义它干嘛。

    下面来看看我们是如何使用命名空间的。

    3. 命名空间的使用

    下面我来介绍命名空间的三种使用方法。

    3.1 加命名空间名称及作用域限定符

    #include <stdio.h>
    
    namespace N
    {
    	int a = 10;
    	int b = 20;
    	int c = 30;
    }
    
    int main()
    {
    	printf("%d\n", N::a);
    	return 0;
    }
    

    代码中的 '::'为域作用限定符 ,N::a的作用是直接指定a变量就是N空间里命名的变量。

    运行结果:
    在这里插入图片描述

    3.2 使用using将命名空间中成员引入

    #include <stdio.h>
    
    namespace N
    {
    	int a = 10;
    	int b = 20;
    	int c = 30;
    }
    
    using N::b;
    
    int main()
    {
    	printf("a = %d\n", N::a);
    	printf("b = %d\n", b);
    	return 0;
    }
    

    using也是c++中的一个关键字,该关键字的作用是展开命名空间。代码中的using N::b指的是把b单独展开在全局域中,展开之后的b就相当于一个没有被封装的全局变量,可以在任何地方调用。

    运行结果:
    在这里插入图片描述

    3.3 使用using namespace命名空间名称引入

    #include <stdio.h>
    
    namespace N
    {
    	int a = 10;
    	int b = 20;
    	int c = 30;
    }
    
    using N::b;
    using namespace N;
    
    int main()
    {
    	printf("a = %d\n", N::a);
    	printf("a = %d\n", b);
    	printf("c = %d\n", c);
    	return 0;
    }
    

    using namespace N相当于将命名空间N里的变量全部展开到全局域中,这样域中所有变量的调用都会不受限制。

    运行结果:
    在这里插入图片描述
    注意:第三种方法并不推荐使用,因为全部展开根本没有起到命名空间的效果。不过第三种方法在展开比较方便,日常练习中可以使用,但如果是在大型项目中还是推荐使用前两种方法。

    4. 命名空间补充知识

    4.1 命名空间里的内容既可以定义变量,也可以定义函数

    //1. 普通的命名空间
    namespace N1 // N1为命名空间的名称
    {
    	// 命名空间中的内容,既可以定义变量,也可以定义函数
    	int a;
    	int Add(int left, int right)
    	{
    		return left + right;
    	}
    }
    

    4.2 命名空间可以嵌套

    //2. 命名空间可以嵌套
    namespace N2
    {
    	int a;
    	int b;
    	int Add(int left, int right)
    	{
    		return left + right;
    	}
    	namespace N3
    	{
    		int c;
    		int d;
    		int Sub(int left, int right)
    		{
    			return left - right;
    		}
    	}
    }
    

    下面我们来看嵌套命名空间是如何来调用的:

    int main()
    {
    	printf("%d\n", N2::a);
    	printf("%d\n", N2::Add(3, 4));
    	printf("%d\n", N2::N3::c);
    }
    

    可以看到嵌套命名空间在展开的时候利用域作用限定符逐层展开即可。

    4.3 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。

    //3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
    
    //a.cpp
    namespace N1 // N1为命名空间的名称
    {
    	// 命名空间中的内容,既可以定义变量,也可以定义函数
    	int a;
    	int Add(int left, int right)
    	{
    		return left + right;
    	}
    }
    
    //b.cpp
    namespace N1
    {
    	int Mul(int left, int right)
    	{
    		return left * right;
    	}
    }
    

    命名空间的介绍到这里就全部结束了,学完命名空间之后大家一定也感受到它的优势了。再拿我最开始的例子来举例,当你和张三在命名变量的时候,你的变量就放在你的命名空间,张三的变量放在他的命名空间中。在项目汇总时,如果要用你的变量就从你的命名空间中取,用它的就从他的命名空间中取,这样就永远不会发生命名冲突了。

    最后希望这篇文章能够为大家带来帮助。

    展开全文
  • 思考:在php中,函数类和...这样的效率和效果都是最好的,但是在大型项目中,不同团队负责的模块可能不同,那么此时就很难保证出现不同名了,因此这个时候就需要引入一种命名空间机制来保证,即使出现了同名结构也不...

    思考:在php中,函数类和常量都是不允许同名的,一旦同名就会出现冲突。但是在大型项目开发中,团队开发很难避免出现同名结构,此时就会出现同名冲突

    解决的方案只能是刻意去控制不同名吗?

    引入:从开发角度出发,最好的办法就是保证不同名。这样的效率和效果都是最好的,但是在大型项目中,不同团队负责的模块可能不同,那么此时就很难保证出现不同名了,

    因此这个时候就需要引入一种命名空间机制来保证,即使出现了同名结构也不影响整个项目。

    命名空间基础【掌握】

    定义:命名空间namespace,是指认为将内存进行分割,让不同内存区域的同名结构共存,从而解决在大型项目中可能出现的重名结构问题。

    1.基本语法 nameapace 空间名字

    namespace my_space;//定义一个叫做my_space的空间

    2.命名空间的命名规则

    由字母、下划线和数字构成

    可以以字母和下划线开头

    较少出现多单词空间名,一个使用下划线法

    3.命名空间的作用:能够创建同名结构,包含函数,常量和类

    namespace my_space;//定义一个叫做my_space的空间

    functionshow(){echo __METHOD__;

    }

    namespace my_space2;$name='30';classposen{functionshow(){echo '同名的函数,也不报错';

    }

    }

    注意,在一个空间中不可以重名。

    4.命名空间里面的内容

    命名空间里面可以定义同名函数、常量和类(结构),因此类结构不允许同名,这些是命名空间规范的目标(称为空间元素)

    命名空间里面可以有其他代码

    namespace my_space;//定义一个叫做my_space的空间

    functionshow(){echo __METHOD__;

    }

    namespace my_space2;$name='30'; //变量

    echo $name; //变量输出

    class posen{ //类

    public $name='杜'; //类属性

    function show(){ //类成员

    echo '同名的函数,也不报错';

    }

    }

    5.命名空间注意事项:命名空间的声明(第一次)必须在所有代码之前

    namespace my_space;//命名空间之前不能有任何代码

    namespace my_space;//错误,第一次命名空间之前不能有任何代码

    注意:命名空间在一个脚本中只会定义一个(最开始),但是在讲课的时候可能会定义多个

    总结

    1.命名空间是使用namespace+空间的名称

    2.不同命名空间可以定义同名函数、常量和类(同名结构)

    3.命名空间里可以书写任意代码

    4.命名空间的定义必须在脚本的最前面

    5.一个脚本中通常只会定义一个空间

    6.命名空间其实就好比是磁盘上划分不同文件夹,用来保存同名文件

    思考:命名空间既然是用来划分空间的,那么能否像文件夹层级那样?实现多层级的命名空间呢?

    引入:命名空间本身就是建立一种虚拟的“围栏”,用来区分不同位置的同名结构,既然可以在内存中设置一层“围栏”,那么自然也可以设置多层,

    这个就叫做子空间

    命名空间子空间【掌握】

    定义:子空间,既在已有的空间上,再在内部进行空间划分,让每个小空间独立起来

    1.命名空间子空间是直接通过namespace+路径符号\ 实现

    namespace my_space;//创建一个一级空间

    functiondisplay(){};//创建一个子空间

    namespace my_space\child; //在my_space空间下创建一个子空间child

    function displat(){};

    2.子空间的创建不一定非要在前面创建了上级空间,即可以直接在某个脚本中创建子空间

    namespace space\parent;function display(){};

    总结:

    1.子空间也是通过namespace实现,用namespace+路径\区分上下级空间名

    2.基于一个脚本中通常只有一个空间名,所以子空间的创建可以直接创建(不用一定先创建一级空间)、

    3.子空间理论上可以创建无限层级,但是实际层级根据项目需求确定(一般不超过四层)

    思考:有了命名空间后,可以在同一个文件里定义不同空间,然后出现同名结构,那如何进行访问呢?

    引入:其实空间就像文件夹一样,同一个文件里不能有同名文件,但是不同文件夹下肯定可以出现同名文件的,而

    如果进行访问的话,就需要进入到不同的空间进行访问。

    空间元素访问【掌握】

    定义:命名空间访问,是指访问不同空间里的结构元素,如果空间里有除了函数、常量和类的其他代码,会自动执行

    只有空间元素本身(函数、常量和类)是需要通过空间进行访问的,在php命名空间中,提供了三种空间元素的访问方式:

    非限定名称,限定名称和完全限定名称。

    1.非限定名称访问:即直接访问空间元素的名字,此类访问的是当前代码所属空间内的元素

    namespace my_space;functionshow(){echo __FUNCTION__;

    }

    namespace my_space3;functionshow(){echo __FUNCTION__;

    }

    //访问空间元素:非限定名称(直接使用结构名字)

    show();//显示的是my_space3 show 调用show函数是在my_space3空间下

    注意:非限定名称访问就好比是访问当前自己文件夹下的所有文件

    2.限定名称访问,即在访问元素的前面使用相应的空间名字,非限定名称的访问时基于子空间来实现的

    namespace my_space\files;functionshow(){echo __FUNCTION__;

    }//定义子空间

    namespace my_space\files1;functionshow(){echo "我是files1子空间";

    }//定义父空间

    namespace my_space;functionshow(){echo "我是父空间";

    }

    show();//父空间访问

    files\show(); //子空间files 实际为当前空间my_space+files\show()

    注意:限定名称访问好比访问当前文件夹下的子文件夹内容

    3.完全限定名称访问,即从根鲁姆(全局)开始访问,使用\作为全局空间开始符号

    namespace files;functionshow(){echo __FUNCTION__;

    }//定义子空间

    namespace files1;functionshow(){echo "我是files1子空间";

    }//定义父空间

    namespace my_space;functionshow(){echo "我是父空间";

    }//在房钱my_space空间下 使用全局限定来访问files中的show结构

    \files\show();//使用 \开始符号 全局限定 返回files show

    注意:完全限定名称访问好比从磁盘根目录访问对应路径下的内容(绝对路径)

    总结:

    1.命名空间的访问分为三种模式

    非限定名称访问:直接访问元素本身,代表当前所属空间(当前目录)

    限定名称访问:使用空间名+元素,代表访问当前空间子空间(当前目录子目录)

    完全限定名称访问:使用全局空间开始,代表从全局开始进行访问(根目录)

    思考:是不是有了命名空间,所有的文件都必须指定空间,如果不指定会怎么样?

    引入:并非所有情况下都需要使用命名空间,命名空间时针对有些可能出现重名的内容时,才会使用的

    另外,如果不使用命名空间,本质系统也认为使用了空间,这就是全局空间

    全局空间【掌握】

    定义:全局空间,即空间元素在没有定义空间的情况下所属的空间,也是所有定义的空间的顶级空间,(即所有空间都是从全局空间分离出来的)

    1.没有指定空间的元素所属空间属于全局空间

    }

    show();//输出无 全局空间没有名字

    2.所有空间本质都是在全局空间下划分的

    namespace space;functionshow(){echo__NAMESPACE__;

    }

    show();//space空间属于从全局空间划分一部分用于space空间管理

    3.全局空间元素访问,使用完全限定名称访问

    }

    show();//非限定名称访问:本身当前就是全局空间内,所以可以访问

    \show(); //完全新丁名称访问,全局符号\+全局空间元素

    4.一旦命名空间出现,那么空间元素(类,常量和函数)的访问就被限定在空间内,如果使用非限定名称访问,那么系统会以下解析(限定名称或者完全限定名称是直接按路径准确找)

    首先,一定是在自己的空间内查找

    如果找不到元素,不同空间元素的处理不同

    系统常量,系统函数如果找不到,会自动去全局空间找(也就是能找到)

    系统类是不会自动去全局空间找的(报错,提示当前所属空间元素找不到)

    namespace space;//访问空间元素 常量

    echo PHP_VERSION; //输出7.0.10 为什么能输出,我当前没有定义这个常量,它会去全局空间找

    //空间元素——函数访问

    echo count(array(1,2,3,4)); //返回4,现在当前空间下找,找不到去找全局空间

    //访问空间类

    $conn=new mysqli('localhost','root','root','senven',3306); //报错 非限定类访问不允许

    //如果想访问需要使用全局限定名称

    $conn=new \mysqli('localhost','root','root','senven',3306);

    5.同样的,如果一个文件有空间,包含了一个没有空间的文件,那么要访问文件中的内容,需要使用全局空间

    //属于全局空间

    functionshow(){echo __FILE__;

    }

    namespace sppace;

    //包含无空间文件include 'space01.php';

    show();//可以访问 访问是sppace空间下的show函数

    namespace sppace;include 'space01.php';

    show();//可以访问 访问space下的空间show函数

    \show(); //正确,访问全局空间下的show函数

    //注意:如果space空间没有show的话,直接访问show函数也是正确的,因为系统会自动寻找全局空间

    总结:

    1.全局空间就是没有使用namespace定义的空间(所有空间本质都是在全局空间下划分)

    2.全局空间的元素访问使用完全限定名称访问

    3.系统内置的函数,常量和类都属于全局空间

    系统 函数,常量在空间内访问的时候系统会自动在自己空间找,如果找不到会去全局空间找

    系统类必须使用全局空间访问:\类名

    思考:既然前面说过一个脚本中通常只会定义一个空间,那么怎么会出现这么多种访问方式呢?

    引入:上述案例只是为了知识本身的规则,在实际应用中一个脚本只会有一个空间,因为一个脚本中通常只有一个类或者一些函数(功能函数)

    但是因为开发的结构性,不同文档所属的功能是不同的,因此也是存放在不同的文件夹的,因此在实现业务的时候会进行文件包含,也就会产生空间包含的问题

    所有就会需要多种访问方式来进行访问。

    命名空间应用【掌握】

    定义:命名空间应用是模拟真实的开发环境,来运用命名空间的规则

    1.创建文件夹:模拟项目不同文件php文件放到不同文件夹下

    --|root                   -------根目录

    --|--|controller                ------业务模块

    --|--|model                  ----数据模块

    --|--|core                  ------核心工具

    2.业务说明

    root根目录:存放用户可以直接访问的文件,文件都是请求controller里的文件

    controller目录:存放业务逻辑文件,所有业务都是类文件,业务要操作数据库,请求model里的文件,属于controller空间

    model目录:存放数据库操作的类文件,一张表一个类文件,属于model空间

    core目录:核心工具的存放,属于core空间

    注意:层层相关,层级结构概念,首先写一个用户操作相关的,需要调用core中的数据库查询(只是个工具),在model数据模型中来想数据库操作(select* from user ),

    在业务逻辑中对model中查询出来的数据进行操作。。。。。。。

    3.创建3个文件:分别代表root目录里下(不需要空间),controller目录下,controller空间,model目录下的model空间

    //core

    core/DB_class.php

    namespace core;classDB{public function__construct(){echo '实现了数据的初始化操作
    ';

    }public function query($sql){echo '能够实现数据的查询
    '.$sql;

    }

    }

    //model

    model/User_class.php

    namespace model;//使用core下的操作数据库的类

    include_once 'D:\wamp\www\root\core\DB_class.php';classUser{public functiongetAllUser(){$sql='select * from user'; //查询所有的访问

    // $user =new DB(); //非限定名称,在model下面找,找不到 错误

    // $user=new core\DB(); //限定名称在model下找core找db 找不大 错误

    $user=new\core\DB();return $user->query($sql);

    }

    }

    //controller

    control/User_class.php<?php //定义空间

    namespace controller;//调用模型目录下的user类实现数据库操作:使用完全限定名称来访问

    include_once 'D:\wamp\www\root\model\User_class.php';//业务逻辑模块

    //显示用户数据

    classUser{public functionindex(){//获取用户表的数据

    $user=new\model\User();$s=$user->getAllUser();echo '实现了用户的业务操作


    '.$s;

    }

    }

    //入口文件

    root/index.php<?php //入口文件

    //找到controller中对应的User_class.php

    include_once 'controller/User_class.php';$u=newcontroller\User();$u->index(); //返回了数据

    //实现了数据的初始化

    //能够实现数据的查询

    //select * from user 实现了用户的业务操作

    代码说明:

    index.php在root目录下没有定义空间,内部元素属于全局空间,index.php包含了子目录controller下的User_class.php,而User类属于controller空间,所以在index.php中访问User类的时候,

    可以使用限定名称(全局的i空间controller\空间元素),或者完全限定名称(\controller\空间元素)

    controller/User_class.php在root\controller文件夹下,定义了空间controller,所以文件里面所有访问,默认都在controller下找,controller/User类中用到了model\User类,所以需要使用完全限定名称访问

    (同级别不同空间)\model\User

    model/User_class.php在root\model文件夹下,定义了model空间,所以文件里面所有访问,默认都在model下面找,model/User类中用到了core\DB类,所以需要使用全局限定名称访问\core\DB

    core\DB_calss.php在root/core文件夹下,定义了空间core

    总结:

    空间的实际应用是以文件为单位定义空间的

    空间的划分是按业务对应的脚本进行划分的,如业务controller,数据model等

    文件的包含和空间的包含没有联系,二者都是独立的,文件是在加载文件时,而空间在进入内存后

    空间应用,通常是采用非限定名称(自己空间里)和完全限定名称访问(其他空间)

    思考:在实际应该开发中,几乎所有文件都有空间,在进行访问的时候每次都需要使用完全限定名称太麻烦了,有没有什么好的方式呢?

    引入:实际开发中,一般都会进行优化,不会直接使用完全限定名称访问的,并且考虑到继承之类,会出现各种文件包含和空间交互,因此

    为了能够简单的时候,可以采用空间元素引入

    命名空间引入【掌握】

    定义:命名空间引入其实就是将另外一个空间的元素(类,函数和常量)引入到当前空间来,当作当前空空间元素访问,从而可以减少复杂的完全限定名称访问,取而代之的是非限定名称

    访问的方式

    1.空间引入的方式:use关键字

    namespace space1;classman{public $name="小伟";public functionshow(){echo $this->name;

    }

    }

    namespace space2;//使用完全限定名称方式访问太过麻烦

    // $obj=new \space1\man();

    // $obj->show();

    //使用use关键字引入空间元素

    usespace1\man;$obj=newman();$obj->show();

    注意:use进行空间包含的时候,默认是从全局空间开始构建空间路径的(不是自己空间的相对路径)所以上述的代码等价于下面的代码

    namespace space2;//使用完全限定名称方式访问太过麻烦

    // $obj=new \space1\man();

    // $obj->show();

    //使用use关键字引入空间元素

    use\space1\man;$obj=newman();$obj->show();

    2.空间引入的元素默认是类,如果要引入其他元素,就必须使用相应的关键字:function和const

    namespace space1;//空间方法

    functionadd(){echo "我是空间add方法";

    }//空间常量

    const SEX='女';//空间类

    classman{public $name="小伟";public functionshow(){echo $this->name;

    }

    }

    namespace space2;//引入空间元素类

    usespace1\man;//引入空间元素方法

    use functionspace1\add;//引入空间元素常量

    use constspace1\SEX;//访问space2空间中的函数

    add();//常量

    echo SEX;

    3.如果被引用的元素在当前空间已经存在,则会出现重名,解决方案是使用别名 as alias

    namespace space1;//空间方法

    functionadd(){echo "我是空间add方法";

    }//空间常量

    const SEX='女';//空间类

    classman{public $name="小伟";public functionshow(){echo $this->name;

    }

    }

    namespace space2;//此空间add

    functionadd(){echo __METHOD__;

    }//由于空间space1中和space2中有同名方法 需要在引入元素的时候为方法起个别名

    use function space1\add ass;

    s();

    add();

    注意:一旦引入的时候使用了别名,那么在使用的时候就直接通过别名使用

    5.如果一个空间有多个元素要引入,那么可以进行一次引入多个使用逗号,分割即可

    namespace space1;//空间方法

    functionadd(){echo "我是空间add方法";

    }functionshow(){

    }//空间常量

    const SEX='女';//空间类

    classman{public $name="小伟";public functionshow(){echo $this->name;

    }

    }classwuman{

    }

    namespace space2;//一次引入多个空间元素,如class function const 必须分开写

    use space1\man,space1\wuman; //一次引用2个类

    use function space1\add,space\show; //一次引入2个函数

    注意:以上方式都是在引入同一种元素,如果要引入多个不同元素,可以如下使用

    namespace space1;//空间方法

    functionadd(){echo "我是空间add方法";

    }functionshow(){echo __METHOD__;

    }//空间常量

    const SEX='女';//空间类

    classman{public $name="小伟";public functionshow(){echo $this->name;

    }

    };classwuman{

    }

    namespace space2;//一次引入space1的类,函数和常量

    usespace1\{

    man,

    function add,

    function show,

    constSEX

    };//注意这个分号是必须的,表示一行结束。

    show();

    6.如果说确定一个空间的所有元素都需要引入进来,也可以直接引入空间

    namespace space1;//空间方法

    functionadd(){echo "我是空间add方法";

    }functionshow(){echo __METHOD__;

    }//空间常量

    const SEX='女';//空间类

    classman{public $name="小伟";public functionshow(){echo $this->name;

    }

    };classwuman{

    }

    namespace space2;//引入空间

    use spcace1;

    注意:如果直接进行空间引入,那么被引入的空间属于当前空间的一个元素,要访问引入空间的其他元素,得从引入空间开始,即引入的空间最后一级空间名字+元素(引入空间当作当前的空间子空间)

    namespace space1;//空间方法

    functionadd(){echo "我是空间add方法";

    }functionshow(){echo __METHOD__;

    }//空间常量

    const SEX='女';//空间类

    classman{public $name="小伟";public functionshow(){echo $this->name;

    }

    };classwuman{

    }

    namespace space2;//引入空间

    usespace1;//访问被引入空间中的元素

    space1\add();

    总结:

    1.空间引入是解决访问时的麻烦,有完全限定名称变成非限定名称访问

    2.空间元素都可以引入,但是引入方式有区别

    类直接引入

    函数需要在use之后添加关键字function

    常量需要在use之后添加关键字const

    3.空间引入过程中如果出现重名,需要使用别名来处理,引入后在空间里可以直接访问别名

    4.可以一次性引入一个空间内的多个元素

    5.如果必须的情况下,也可以直接使用空间引入,但是注意被引入空间的元素不允许直接使用非限定名称访问

    必须使用被引入空间的最后一级空间+元素访问(不常使用,引入方便但是使用不方便)

    引入名称空间的类、方法、常量

    //引入命名空间的类、方法和常量

    use\China\student;use const China\PI;use functionChina\show;

    show();echo "
    ";echo PI;

    给引入的方法 类 常量去别名

    //引入命名空间类,并且把这个类取个别名,防止类的重名

    use \China\student asstu;$obj= newstu();var_dump($obj);

    展开全文
  • python-命名空间

    2020-12-22 23:25:34
    通俗的来说,Python中所谓的命名空间可以理解为一个容器。在这个容器中可以装许多标识符。...第二,函数定义(包括def和lambda)产生新的命名空间。第三,python搜索一个标识符的顺序是"LEGB"。所谓的"LEGB"是pyt...

    通俗的来说,Python中所谓的命名空间可以理解为一个容器。在这个容器中可以装许多标识符。不同容器中的同名的标识符是不会相互冲突的。理解python的命名空间需要掌握三条规则:

    第一,赋值(包括显式赋值和隐式赋值)产生标识符,赋值的地点决定标识符所处的命名空间。

    第二,函数定义(包括def和lambda)产生新的命名空间。

    第三,python搜索一个标识符的顺序是"LEGB"。

    所谓的"LEGB"是python中四层命名空间的英文名字首字母的缩写。

    最里面的一层是L(local),表示在一个函数定义中,而且在这个函数里面没有再包含函数的定义。

    第二层E(enclosing function),表示在一个函数定义中,但这个函数里面还包含有函数的定义,其实L层和E层只是相对的。

    第三层G(global),是指一个模块的命名空间,也就是说在一个.py文件中定义的标识符,但不在一个函数中。

    第四层B(builtin),是指python解释器启动时就已经具有的命名空间,之所以叫builtin是因为在python解释器启动时会自动载入__builtin__模块,这个模块中的list、str等内置函数的就处于B层的命名空间中。

    这三条规则通过一个例子来看比较明白。如下面例子所示:

    来详细看看这段代码中的标识符。第1行,适用第一条规则“赋值产生标识符”,因此产生一个标识符g。“赋值的地点决定标识符所处的命名空间”,因为g是没有在一个函数定义中,因此g处于'G'层命名空间中。这一行中还有一个标识符,那就是int。那么int是在什么地方定义的呢?由于int是内置函数,是在__builtin__模块中定义的,所以int就处于'B'的层命名空间中。第2行,适用第一条规则,由于def中包含一个隐性的赋值过程,这一行产生一个标识符outFunc,outFunc并不处于一个函数定义的内部,因此,outFunc处于'G'层命名空间中。此外,这一行还适用第二条规则,产生一个新的命名空间。第3行,适用第一条规则,产生个标识符e,而且由于这是在一个函数定义内,并且内部还有函数定义,因此e处于'E'层命名空间中。第4行要注意,适用第一条规则,产生一个标识符g,这个g与e一样外于'E'层命名空间中。这个g与第一行的g是不同的,因为所处的命名空间不一样。第5行,适用第一条规则,产生一个处于'E'层命名空间的标识符inFunc。与第2行一样,这一行定义函数也产生一个新的命名空间。

    第6行,适用第一条规则,产生一个标识符l,由于这个l处于一个函数内部,而且在这个函数内部没有其他函数的定义,因此l处于'L'层命名空间中。

    第7行,适用第三条规则,python解释器首先看到标识符g,按照LEGB的顺序往上找,先找L层(也就是在inFunc内部),没有。再找E层,有,值为10。因此这里的g的值为10。寻找过程到为止,并不会再往上找到'G'层。寻找e的过程也一样,e的值为2。因此第9行的结果为12。

    其实,所谓的“LEGB”是为了学术上便于表述而创造的。让一个编程的人说出哪个标识符处于哪个层没有什么意义,只要知道对于一个标识符,python是怎么寻找它的值的就可以了。其实找值的过程直观上也很容易理解。

    通过上面的例子也可以看出,如果在不同的命名空间中定义了相同的标识符是没有关系的,并不会产生冲突。寻找一个标识符的值过程总是从当前层开始往上找的,首先找到的就为这个标识符的值。也由此可以这么说,'B'层标识符在所有模块(.py文件)中可用;'G'层标识符在当前模块内(.py文件)中可用;'E'和'L'层标识符在当前函数内可用。

    可以看到,虽然有两个层中的g,但使用了global语句后,就是指'G'层的标识符。也就是第7行中的g,就是指第1行产生的那个g,值为'global'。

    最后说一句,其实只要在编程的时候注意一下,不要使用相同的标识符,基本上就可以避免任何与命名空间相关的问题。还有就是在一个函数中尽量不要使用上层命名空间中的标识符,如果一定要用,也最好使用参数传递的方式进行,这样有利于保持函数的独立性。

    展开全文
  • C#类与命名空间

    千次阅读 2021-08-18 23:15:26
    本文章包括这样几个类容,首先是剖析Hello World程序,上篇文章分别用十种技术编写了Hello World程序,其中有简单的也有复杂的,本片文章将剖析其中最简单的,也就是ConsoleApplication,通过剖析这个程序,来让大家...
  • C++匿名命名空间

    2021-03-15 09:53:31
    定义一个命名空间时,可以忽略这个命名空间的名称: namespce { char c; int i; double d; } 编译器在内部会为这个命名空间生成一个唯一的名字,而且还会为这个匿名的命名空间生成一条using指令。所以上面的...
  • 命名空间与LEGB规则之前隐隐约约提到过一些关于Python赋值语句的特殊性的问题,这个问题的根源就在于Python中的变量的命名空间机制和之前熟悉的C也好java也好都不太一样。■ 命名空间所谓命名空间,就是指根据代码...
  • 命名空间定义了上下文,就是定义了一个范围。一个文件夹 (目录) 中可以包含多个文件夹,每个文件夹中不能有相同的文件名,但不同文件夹中的文件可以重名。 1. 命名空间 命名空间定义使用关键字 namespace,后跟...
  • C++命名空间

    2021-06-16 19:15:18
    大型应用程序经常使用来自不同厂商的开发库,几乎不可避免会使用相同的名字,也就是说一个库中定义的名字可能与其他库中的名字相同...命名空间是用来限定名字的解析和使用范围的,他是C++开发大型程序的工具之一 ...
  • > 可以定义任意数量的use语句,或使用逗号分隔成独立的命名空间,在这个例子中我们导入了AppLib2命名空间,但我们仍然不能直接引用MYCONST,MyFunction和MyClass,因为我们的代码还在全局空间中,但如果我们添加了...
  • C++命名空间与缺省参数

    多人点赞 热门讨论 2021-09-27 18:04:36
    使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。 int a = 10; int main(void) { int a = 10; return 0; } ...
  • C#中的命名空间

    2021-10-21 12:11:21
    就像上面定义里说的, 在较大的项目中,开发人员有很多,我们的代码可能和其他开发者的代码使用相同的类名、接口名、函数或常量名,如果不使用命名空间,使用名称时会起冲突。而使用命名空间将代码放到唯一的厂商...
  • 一:命名空间概念:命名空间是一种封装事物的方法,类似于目录和文件。命名空间解决的问题(手册上也写的很清楚,下面按照自己的理解简化了):1:解决程序编写者自己写的类、常量、函数和php内部的或...
  • 一、命名空间 假设这样一种情况,当一个班上有两个名叫 Zara 的学生时,为了明确区分它们,我们在使用名字之外,不得不使用一些额外的信息,比如他们的家庭住址,或者他们父母的名字等等。 同样的情况也出现在 C++ ...
  • 放在.cpp文件中是比较安全的,文件在多次递归包含后很容易出现一些定义和声明上的问题。 放在cpp中可以减小头文件依赖,可以提高编译速度。所以,能放在cpp中的,就不要放在h中。 只有头文件必须用到的放到头文件,...
  • XML命名空间详解

    2021-01-10 23:39:14
    文章目录XML文件命名空间定义解释 XML文件命名空间 观察下面这个xml文件(spring框架文件头): <?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ...
  • C/C++编程:命名空间

    2021-01-08 10:47:26
    为什么要引入命名空间 当你采用不同的模块和程序库时,经常会出现冲突现象,这是因为不同的模块和程序库可能针对不同的对象使用相同的标志符。 namespaces(命名空间)可以解决这个问题 什么是namespaces namespaces...
  • C#学习笔记 命名空间

    2021-02-26 16:37:43
    命名空间是一些类型的松散的集合,一般不要求处于同一命名空间的类有明确的相互关系,如包含、继承等。为了方便编程和管理,通常把需要在一起工作的类型放在一个命名空间里。如System命名空间下有各种类和接口,包括...
  • 一个中大型软件往往由多名程序员共同开发,会使用大量的变量和函数,不可避免地会出现变量或函数的命名冲突。当所有人的代码都测试通过,没有问题时,将它们结合到一起就有可能会出现命名冲突。例如小李和小韩都参与...
  • 1、命名空间I) 定义: 1)命名空间(Namespace)是从名称到对象的映射,大部分的命名空间都是通过 Python 字典来实现的。 2)命名空间提供了在项目中避免名字冲突的一种方法。 3)各个命名空间是独立的,没有任何关系的,...
  • c++命名空间

    2021-11-07 10:16:42
    命名空间(namespace),是c++引入的一种机制,namespace目的是用来解决全局变量名与函数名或函数名与函数名之间名称相同的冲突的。c语言没有namespace,从c扩展而来的c++早期也没有,后来的c++、java、python都使用...
  • 命名空间

    2020-12-21 19:06:50
    XML中命名空间的概念
  • 一个中大型软件往往由多名程序员共同开发,会使用大量的变量和函数,不可避免地会出现变量或函数的命名冲突。当所有人的代码都测试通过,没有问题时,将它们结合到一起就有可能会出现命名冲突。例如小李和小韩都参与...
  • 它可以为不同的命名空间从逻辑上提供独立的网络协议栈,具体包括网络设备、路由表、arp表、iptables、以及套接字(socket)等。使得不同的网络空间就都好像运行在独立的网络中一样。 你是不是和飞哥一样,也很好奇 ...
  • XML 模式:了解命名空间 作者:Rahul Srivastava ... 定义 XML 命名空间的主要动机之一是在使用和重用多个词汇时避免名称冲突。XML 模式用于为 XML 实例创建一个词汇并频繁使用命名空间。因...
  • 1、命名冲突(不使用命名空间有啥问题) 在 XML 中,元素名称是由开发者定义的,当两个不同的文档使用相同的元素名时,就会发生命名冲突。 这个 XML 文档携带着某个表格中的信息: <table> <tr> <...
  • 在一个命名空间中声明的类的名称与另一个命名空间中声明的相同的类的名称不冲突。 我们举一个计算机系统中的例子,一个文件夹(目录)中可以包含多个文件夹,每个文件夹中不能有相同的文件名,但不同文件夹中的文件...
  • 我创建了一个名为“ List”的控制器,然后需要创建一个类的对象,该对象编码在一个文件中,该文件已被include_once()包含在其中,如图所示,namespace App\Http\Controllers;use App\Http\Controllers\Controller;$...
  • c++/qt命名空间分析

    2021-03-15 16:53:45
    命名空间定义: namespace Ui { class MainWindow; //命名空间内可以放变量,函数,结构体,类等等 } 外部使用MainWindow类: Ui::MainWindow方式。 在使用者源码文件开头,using namespace Ui;,这样就...
  • 一、解决方案、项目、程序集、命名空间初学者很容易把这些概念搞混淆。先说说项目(Project),通俗的说,一个项目可以就是你开发的一个软件。在.Net下,一个项目可以表现为多种类型,如控制台应用程序,Windows应用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 74,800
精华内容 29,920
关键字:

命名空间包含冲突的定义