C++进阶(一)之命名空间

Namespaces provide a method for preventing name conflicts in large projects.

命名空间的定义

  • 命名空间是由关键字 **namespace ** 和一对花括号 {} 组成。
  • 可以出现在 全局作用域 中的声明都可以在 namespace 内出现,包括类、变量、函数、模版和其他命名空间。

命名空间的三个特性

可开放性

  • 同一个命名空间可在程序不同地方添加声明
  • 通常情况下,不能将 #include 放在命名空间内部
  • 在命名空间外定义该命名空间中的成员时,需要明确其所属的命名空间
#include <iostream>

namespace apple{
  	class A{
      
    };
  	void func_first(){
     		std::cout << "apple::func_first() " << std::endl;
    }
}

namespace apple{
  	class B{
      	
    };
  	void func_second();
}

void apple::func_second(){
     std::cout << "apple::func_second() " << std::endl;
}

int main(){
  	apple::func_first();
  	apple::func_second();
  	
  	return 0;
}

可嵌套性

  • 可嵌套性指命名空间中可以嵌套其他的命名空间
#include <iostream>

namespace fruit{
  	namespace apple{
      	class A{
          
        };
      	void func(){
          	std::cout << "fruit::apple::func() " << std::endl;
        }
    }
}

int main(){
  	fruit::apple::func();
  	return 0;
}

可匿名性

  • 匿名命名空间指 关键字namespace 后紧跟 花括号{} ,无名称的命名空间
  • 匿名命名空间的变量拥有 静态生命周期 :在第一次时被创建,直到程序结束才销毁
  • 与其他命名空间不同,匿名命名空间仅在特定文件中有效,其作用域不能横跨多个文件
int i;
namespace {
  	int i;
}

i = 10;		// 错误,匿名命名空间中的变量是静态变量,相当于 static i;
					//		  且 其作用域与namespace 相同,出现二义性

可内联性

  • 对于 使用关键字 inline 声明的命名空间称为 内联命名空间
  • 内联命名空间可直接被外层命名空间使用
#include <iostream>

inline namespace apple{
  	class A{
      
    };
  	void func_first(){
     		std::cout << "apple::func_first() " << std::endl;
    }
}

namespace fruit{
  	inline namespace apple{
      	class A{
          
        };
      	void func(){
          	std::cout << "fruit::apple::func() " << std::endl;
        }
    }
}

int main(){
  	func_first();
  	fruit::func();
  	return 0;
}

两种使用命名空间成员的方式

using 声明

  • using 声明语句一次仅引入命名空间的一个成员
  • 作用域:从 using 声明开始,到using 声明所在作用域结束为止
  • 可出现在 全局作用域、局部作用域、命名空间作用域及类的作用域中
#include <iostream>

namespace apple{
  	void func(){
      	std::cout << "apple::func()" << std::endl;
    }
  	int apple_size = 5;
}

namespace orange{
  	int orange_size = 4;
  	void compare(){
      	using apple::apple_size;
      	std::cout << "orange::size - apple::size = " << orange_size - apple_size << std::endl;
    }
}

int main(){
  	orange::compare();
  	return 0;
}

using 指示

  • using 指示将 namespace 中的所有变量引入到 using 指示所在的所用域
  • 作用域:从 using 指示开始,到using 指示所在作用域结束为止
  • using 指示将命名空间的成员提升至包含命名空间本身using 指示最近作用域
namespace A {
    int i;
}
namespace B {
    int i;
    int j;
    namespace C {
        namespace D {
            using namespace A; // 注入所有来自 A 的名称到全局命名空间
            int j;
            int k;
            int a = i; // i 是 B::i,因为 B::i 隐藏 A::i
        }
        using namespace D; // 注入来自 D 的名称到 C
                           // 注入来自 A 的名称到全局命名空间
        int k = 89; // 声明与用 using 引入者等同的名称 OK
        int l = k;  // 歧义:C::k 或 D::k
        int m = i;  // OK:B::i 隐藏 A::i
        int n = j;  // OK:D::j 隐藏 B::j
    }
}
  • 在使用 using 指令指名某命名空间后,若该命名空间被扩充并向其添加了额外的成员和/或 using 指令,则这些额外成员和额外的命名空间通过该 using 指令可见(与 using 声明相反)
 namespace D {
    int d1;
    void f(char);
 }
 using namespace D; // 引入 D::d1、D::f、D::d2、D::f,
                    // E::e 及 E::f 到全局命名空间!
  
 int d1; // OK:声明时与 D::d1 不冲突
 namespace E {
     int e;
     void f(int);
 }
 namespace D { // 命名空间扩展
     int d2;
     using namespace E; // 传递性 using 指令
     void f(int);
 }
 void f() {
     d1++; // 错误:歧义:::d1 或 D::d1?
     ::d1++; // OK
     D::d1++; // OK
     d2++; // OK,d2 是 D::d2
     e++; // OK:e 是 E::e,因为传递性 using
     f(1); // 错误:歧义:D::f(int) 或 E::f(int)?
     f('a'); // OK:仅有的 f(char) 是 D::f(char)
 }

注:在任何命名空间作用域中的 using 指令 using namespace std;,将命名空间 std 中的所有名字都引入到全局命名空间中(因为全局命名空间是同时包含 std 和任何用户声明命名空间的最近命名空间),这可能导致不合预期的名字冲突。通常认为,在头文件的文件作用域中采用它或其他的 using 指令是不良的实践。

参考

  1. C++ Primer
  2. cppreference 之命名空间
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值