• using 与名字查找


    在编程中经常用到 using namespace std和 using std::cout,这两个语句似乎干的是一样的工作--减少要敲的字母,但仔细推敲下来,它们的语义差别还是挺大的。

    View Code
    #include<cstdio>
    
    namespace test
    {
        void output(){puts("namespace");}
    }
    
    void output(){puts("no   namespace");}
    
    
    int main(int argc,char **argv)
    {
        output();//print "no namespace"
        using test::output;
        output();//print "namespace"
        //using namespace output; //编译错误,output重定义
        //output();
        return 0;
    }

    由以上代码来看

          1.using test::output  使test名字空间里的 output 覆盖了全局名字空间里的 output。

      2.using namespace test 会产生重定义错误,说明没有发生覆盖,说明using namespace不等同于 对 test名字空间里的所有名字使用 using test::***。

    再看以下代码:

    View Code
    #include<cstdio>
    
    namespace test
    {
        int x=3;
    }
    
    int x=5;
    
    int main(int argc,char **argv)
    {
        int x=6;
        printf("%d\n",x); //6
    
        using test::x;    //编译错误,重定义。
        printf("%d\n",x);
        return 0;
    }

        前两行说明符号表是有优先级的,会产生覆盖作用。 当前作用域的符号表的优先级高于全局作用域的符号表。using test::x产生了重定义的错误,由此可见,test::x和main里面定义的x在一个符号表里了。所以using test::x的作用就是将test::x加入当前作用域的符号表。

    View Code
    #include<cstdio>
    namespace test
    {
        int x=3;
    }
    
    int x=5;
    
    int main(int argc,char **argv)
    {
        int x=6;
    
        using namespace test;
    
        printf("%d\n",x);
    
        return 0;
    }

        以上代码并没有产生重定义错误,输出结果是6。说明namespace引入的名字的优先级比当前作用域的要低。

    View Code
    #include<cstdio>
    namespace test
    {
        int x=3;
    }
    
    int x=5;
    
    int main(int argc,char **argv)
    {
        using namespace test;
        printf("%d\n",x);
        return 0;
    }

        上面的代码又产生了重定义错误,说明using namespace引入的符号表的优先级与全局作用域里的符号表的优先级一样,都比当前作用域里的符号表的优先级低。

        总结起来,就是 using的作用就是将名字引入当前作用域的符号表,而using namespace 相当于将namespace的所有名字释放到全局作用域中。

        另外还能看到的是,编译器在查找名字时先查找当前作用域,再查找全局作用域。如果引入类,这相查找规则又发生了什么变化呢?

        

    #include<cstdio>
    
    int x=3;
    
    class base
    {
    
        public:
        base():x(5){};
        int x;
    };
    class test :public base
    {
    public:
    void output()
    {
        int x=4;
        printf("%d",x);
    }
    test():x(1){}
    private:
        int x;
    };

    通过将函数成员中声明的x与类里声明的、基类声明的、全局作用域声明的相互比较,得出结论:编译器先查找当前成员函数,再查找当前类作用域,然后查找基类作用域,最后查找全局作用域。高优先级作用域中的名字会覆盖低优先级中的名字。另在实验中也发现private声明不对查找规则产生影响。

        所有名字查找都遵守以上规则,但函数名查找有其特殊性。首先,类的成员函数要通过对象来调用,这就限定了查找只能在该类和其基类中进行。其次,函数名查找有一种“实参相依”的查找规则:在查找函数时也要到其参数所在名称空间中去查找。这个规则用于非成员函数。

    namespace Test{
      class X{...};
    void f(const X&);
    void g(X*);
    };
     
    //...
    int g(Test::X *);
     
    void fun(){
      Test::X a;
    f(a);
    g(&a);//错误,有歧义
    a = a + a;
    };

      补记:以上所说的其实是关于namespace的几条规则:1.当前作用域,全局作用域、类作用域都可看做名字空间。2.namespace是可嵌套的,也可说成是可分层的,即一个namespace里有别的namespace。3.最上层的名字空间是全局作用域,其它名字空间都是它的子名字空间。4.编译器在查找名字的顺序是先查找当前名字空间,然后依次查找父名字空间。5.using 将名字加入到当前名字空间。6.using namespace nm将nm合并到全局作用域。7.using 和using namespace的效用只限于当前作用域。8.未命名的名字空间会被合并到全局作用域。

        

  • 相关阅读:
    [Linux]Ubuntu下正确挂载NTFS磁盘的方法
    Google搜索指令与自定义引擎
    【Linux】Android手机在Ubuntu上无法被adb识别解决办法(权限相关)
    [ Linux ] Remove PPA source from your pc
    一键去除 UC浏览器 论坛模式 内置的广告
    Huawei U8825d 对4G手机内存重新分区过程[把2Gb内置SD卡容量划分给DATA分区使用]
    【Android】把Linux GCC安插在Android手机上
    [Windows]隐藏文件及目录的命令
    Linux压缩包简体中文乱解决方案[全]
    修改su密码 macbook
  • 原文地址:https://www.cnblogs.com/vsuu/p/2653389.html
Copyright © 2020-2023  润新知