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.未命名的名字空间会被合并到全局作用域。

    

原文地址:https://www.cnblogs.com/vsuu/p/2653389.html