C++ namespace及其作用域

关于namespace

  由于大型程序常会使用多个独立开发的库,这些库又会定义大量全局的类、函数、模板等,不可避免的会发生某些名字相互冲突的情况,多个库将名字放置在全局命名中将导致命名空间污染。为防止名称冲突,可使用多个命名空间将全局的命名空间为不同的作用域。
  一般而言,命名空间可由关键字namespace和名称组成,在单个文件内部使用也可单独由namespace关键字组成一个命名空间,称为未命名的命名空间,其中定义的变量拥有静态生命周期(在第一次使用前创建,直到程序结束才销毁)

namespace graph{
    template<typename T>
    class DenseGraph{
    private:
        T y;
    public:
        DenseGraph(T y):y(y){}
        ~DenseGraph(){}
    };
    // 命名空间可以嵌套
    namespace edge{
        ...
    }
    // 命名空间可以内联
    inline namespace vertix{
        ...
    }
}

namespace{
    template<typename T>
    class DenseGraph{
    private:
        T y;
    public:
        DenseGraph(T y):y(y){}
        ~DenseGraph(){}
    };
}

using声明、指示与作用域

  using指示是以关键字using开头,后面是关键字namespace及其名字,using指示可以出现在全局作用域、局部作用域和命名空间作用域中,但不能出现在类的作用域中,using指示使得某个命名空间中所有的名字都可见。而using声明一次只引入命名空间的一个成员,且可出现在任何地方。

// using声明
std::vector<int> x(10);
std::cout << x << std::endl;

// using指示
namespace test{
    int i=10, j=20;
}
int i = 100;                  //正确,不与test中i冲突
void fun(){
    using namespace test;     //引入命名空间test的名字
    cout << test::i <<" "<< j <<endl;   //使用test的变量
    ++i;                      //错误,不知道使用的哪个i
    cout << ++::i <<endl;     //全局i自加
    cout << ++test::i <<endl; //test中的i自加
    int j = 50;               //正确,当前局部的变量
    cout << ++j <<endl;       //局部变量自加
}

运行得到结果如下:
10 20
101
11
51

注意1: 使用using指示一次性将某个命名空间的所有成员名字变得可见,如果通过using指示使用了多个库,则可能会出现命名空间污染

类、命名空间与作用域

  对命名空间内部名字的查找由内向外依次查找每个外层作用域,外层作用域也可能是一个或多个嵌套命名空间,直到最外层的全局命名空间查找过程终止。

namespace A{
    int i;
    namespace B{
        int i;          //B中隐藏了A::i
        int j;
        int fun1(){
            int j;      //j是局部变量,隐藏了A::B::j
            return i;
        }
    }       //namespace B结束,B中定义的名字不再可见
    int fun2{
        return j;   //错误,j没有定义
    }
    int j = i;      //用A::i进行初始化
}

namespace A{
    int i,k;
    class test{
    public:
        test():i(0,j(0)){}      //正确,初始化test::i和test::j
        int fun1(){return k;}   //返回A::k
        int fun2(){return h;}   //错误,未定义h
        int fun3();
    private:
        int i,j;
    };
    int h = i;
}
int A::test::fun3(){return h;}  //正确,返回A::h

  当类声明一个友元时,该友元声明并没有使得友元本身可见,但一个另外的未声明的类或函数如果第一次出现在友元声明中,则认为它是最近的外层命名空间成员。

namespace A{
    class test{
        friend void fun();
        friend void f(const test&);
    };
}
int main(){
    A::test obj;
    f(obj);     //正确,通过在A::test中的友元声明找到A::f
    fun();      //错误,A::fun没有被声明
}

namespace与重载

//实参相关的重载
namespace A{
    class test{}
    void display(const test&){}
}
class test2:public A::test{}
int main(){
    test2 t;
    display(t);
    return 0;
}

//using指示与重载
namespace A{
    extern void print(int);
    extern void print(double);
}
void print(const std::string &);    //普通声明
using namespace A;
void fun(int val){
    print("valuse: ");  //全局print函数
    print(val);         //调用A::print(int)
}

//多个using指示的重载
namespace A{
    int print(int);
}
namespace B{
    double print(double);
}
using namespace A;
using namespace B;
long print(long);
int main(){
    print(1);   //调用A::print(int)
    print(3.1415);  //调用B::print(double)
    return 0;
}

References:

  • 《Primer c++》第五版
原创文章 38 获赞 13 访问量 4031

猜你喜欢

转载自blog.csdn.net/qq_36287943/article/details/104600864