C++ 命名空间

发布时间 2024-01-06 22:36:33作者: 3的4次方

C++ 命名空间

命名空间用于解决合作开发时的名字冲突问题。

1、namespace关键字

用于定义命名空间。

//定义命名空间
namespace name{
    //variables, functions, classes
}
//使用命名空间内的成员
name::成员名;

name是命名空间的名字,它里面可以包含变量、函数、类、typedef、#define 等。

::是作用域运算符,在C++中用来指明要使用的命名空间。

  • 只能在全局范围内定义,不能在函数内部定义。

  • 命名空间可嵌套定义(一个namespace嵌套一个namespace,使用时连续使用作用域解析符 ::

  • 如果include了using了某个命名空间的其他文件到当前文件,则using的效果会被传播到当前文件。

  • 如果将一个命名空间拆分到多个文件中来写,则如下:

    // name.h
    namespace A{
        extern int x;
        void func();
    }
    // name.cpp
    namespace A{
        int x = 2;
        void func(){std::cout<<"haha";}
    }
    
  • 命名空间是开放的,即可以随时把新的成员加入已有的命名空间中

    namespace A{
    	int a = 10;
        namespace B{
            int b = 11;
        }
    }
    namespace A{//往A中加入一个func
    	void func(){
    		cout << "hello namespace!" << endl;
    	}
    }
    void test(){
    	cout << "A::a : " << A::a << endl;
        cout << "A::B::b :" << A::B::b << endl;
    	A::func();
    }
    
  • 命名空间内的成员声明和定义可以分离(命名空间体内声明函数签名,命名空间外用::定义)

  • 无名命名空间:无名命名空间中的标识符只能在本文件内访问,相当于给这个标识符加上了static,使得其可以作为内部连接

    namespace{
    	int a = 10;
    	void func(){ cout << "hello namespace" << endl; }
    }
    
  • 全局命名空间:定义变量、函数或其他标识符时,如果没有放置在任何命名空间中,则属于全局命名空间。全局命名空间中的标识符可以被整个程序中的任何地方访问。使用::来强制使用全局命名空间:

    // 全局命名空间
    int x = 5;
    // 一个普通命名空间
    namespace MyNamespace {
        int x = 10;
    }
    int main() {
        // 使用全局命名空间中的x
        std::cout << "Global x: " << ::x << std::endl;
        // 使用普通命名空间中的x
        std::cout << "Namespace x: " << MyNamespace::x << std::endl;
    }
    
  • 命名空间可以起别名

    namespace veryLongName{
    	int a = 10;
    	void func(){ cout << "hello namespace" << endl; }
    }
    void test(){
    	namespace shortName = veryLongName; // 起别名
    	cout << "veryLongName::a : " << shortName::a << endl;
    	veryLongName::func();
    	shortName::func();
    }
    

关于嵌套命名空间的补充

1.什么是嵌套命名空间?

嵌套命名空间就是在命名空间里面在定义其它的命名空间,就像是俄罗斯套娃。

namespace np1 {
namespace np2 {
namespace np3 {}
}  // namespace np2
...
}  // namespace np1

2.实验

2.1 外部引用嵌套命名空间内的符号

情况一

#include <iostream>
using namespace std;
namespace np1 {
namespace np2 {
void func2() {
    cout << "np1::np2::func2" << endl;
}
}  // namespace np2
void func1() {
    cout << "np1::func1" << endl;
}
}  // namespace np1
int main() {
    np1::func1();
    np1::np2::func2();
    return 0;
}

实验结果:

表明嵌套命名空间的引用是符合namespace语法的,没有特殊之处。

情况二

using namespace np1;
int main() {
    func1();
    np2::func2();
    return 0;
}

输出结果一样。

2.2 命名空间内容不同层次间符号的引用

情况一:第一层调用第二层

#include <iostream>
using namespace std;
namespace np1 {
namespace np2 {
void func2() {
    cout << "np1::np2::func2" << endl;
}
}  // namespace np2
void func1() {
    np2::func2();
}
}  // namespace np1
int main() {
    np1::func1();
    return 0;
}

实验结果:

表明在命名空间内部的不同层次符号引用依然遵循namespace语法。

情况二:第二层调用第一层

#include <iostream>
using namespace std;
namespace np1 {
void func1() {
    cout << "np1::func1" << endl;
}
namespace np2 {
void func2() {
    func1();  // np1::func1();
}
}  // namespace np2
}  // namespace np1
int main() {
    np1::np2::func2();
    return 0;
}

实验结果:

表明np1相对于np2来说,是默认命名空间。

情况三:第二层调用第一层,但是第一层和第二层存在相同的符号

#include <iostream>
using namespace std;
namespace np1 {
void func1() {
    cout << "np1::func1" << endl;
}
namespace np2 {
void func1() {
    cout << "np1::np2::func1" << endl;
}
void func2() {
    func1();
}
}  // namespace np2
}  // namespace np1
int main() {
    np1::np2::func2();
    return 0;
}

实验结果:

表明np2优先会调用自己内部的符号。正如一个函数的内部,它会优先调用自己的局部变量,接着才考虑寻找外部变量。

2、using关键字

用于声明命名空间中的单个成员或声明整个命名空间,使得指定的标识符可用。

//声明单个成员
using name::成员名;
//声明整个命名空间
using namespace name;

(1)一个cpp文件里可以使用多个using语句。

using namespace A;
using namespace B;

如果编译器发现某个名字在多个缺省的名字空间都出现过,会显示编译错误,这时就必须使用::操作符强行指定名字空间了。
例如你自己定义了一个变量,名字也叫cout。这时你就必须指定是std::cout还是::cout

(2)using声明碰到函数重载:如果命名空间包含一组用相同名字重载的函数,using声明就声明了这个重载函数的所有集合。

namespace A{
	void func(){}
	void func(int x){}
	int  func(int x,int y){}
}
void test(){
	using A::func;
    //所有的func均可用
	func();
	func(10);
	func(10, 20);
}