02~C++名字空间

1.1 namespace 引入

看代码,看结果

// namespace.cpp
#include <iostream>

namespace Department_X {
	static int id = 99;
	void fool(void)
	{
		std::cout << "departmentX" << std::endl;
	}
}

namespace Department_Y {
	static int id = 88;
	void fool(void)
	{
		std::cout << "departmentY" << std::endl;
	}
}



int main()
{	
	/*打印出部门X所有的id变量*/
	std::cout << Department_X::id << std::endl;
	/*使用部门X所有的fool函数*/
	Department_X::fool();

	/*打印出部门Y当中的id变量*/
	std::cout << Department_Y::id << std::endl;
	/*使用部门Y所有的fool函数*/
	Department_Y::fool();

	return  0;
}

输出如下:
99
departmentX
88
departmentY

对于名字空间(英文名 namespace ),我们可以这样理解:
名字空间A里有自己的函数或变量
名字空间B里有自己的函数或变量
名字空间A和B中的函数或者变量可以相互重名,不冲突

如果我们想要访问名字空间的数据的话,最直接的方法是指出名字空间,形如:

#名字空间std中的cout、endl
std::cout
std::endl

#名字空间Department_X中的变量id,函数fool
Department_X::id
Department_X::fool()

1.2 namepace 调用方式优化

喜欢便捷的读者,可能会提出这样一个疑问:
每次使用名字空间里的变量或者函数,我都要不厌其烦的在前面写一个 空间名字::函数名,假如我要访问数百个名字空间中的函数,我就要写数百个名字空间名!!!多么可怕

C++ 提供了另一种简洁的方式,使用形式using namespace xxx的格式,将影响名字空间xxx中的函数或变量的可见性

// namespace.cpp
#include <iostream>
/*在文件作用域中被引入可见性,后面所有的函数都不必调用类似std::cout,std::endl 啦*/
using namespace std;

namespace Department_X {
	static int id = 99;
	void fool(void)
	{
		cout << "departmentX" << endl;
	}
}

namespace Department_Y {
	static int id = 88;
	void fool(void)
	{
		cout << "departmentY" << endl;
	}
}
/*函数bar1 引入Department_X的可见性*/
void bar1(void)
{
	using namespace Department_X;
	cout << "bar1 ";
	/*自然是部门X中的那个fool()函数咯*/
	fool();
}
/*在函数bar2 引入Department_Y的可见性*/
void bar2(void)
{
	using namespace Department_Y;
	cout << "bar2 ";
	/*自然是部门Y中的那个fool()函数咯*/
	fool();
}

int main()
{	
	bar1();
	bar2();
	return  0;
}

1.3 再探名字空间:名字隐藏

// namespace.cpp
#include <iostream>
using namespace std;

namespace Department_X {
	static int id = 99;
	void fool(void)
	{
		cout << "departmentX" << endl;
	}
}


void bar1(void)
{
	using namespace Department_X;
	cout << "bar1 ";
	/*读者会发现,此时的id是部门X中的那个*/
	cout << "id = " << id << " &id = " << &id << endl;
	
	/*此时又定义了一个新的id,它是一个栈地址,为什么不再是部门X中的那一个了呢? 
	解释就是using namespace xxx 只做到将名字空间中的符号可见性给调用者,但是并不是把变量给生硬的引用在这里*/
	int id = 299;
	cout << "id = " << id << " &id = "<< &id <<  endl;
}



int main()
{	
	bar1();
	return  0;
}

为了理解我们还有下面的编程风格(变量引入到作用域,而非可见性)

// namespace.cpp
#include <iostream>
using namespace std;

namespace Department_X {
	static int id = 99;
	void fool(void)
	{
		cout << "departmentX" << endl;
	}
}


void bar1(void)
{
	//这样就是真的把部门X中的变量id引用弄到这个函数里啦!!!
	using Department_X::id;
	cout << "bar1 ";
	cout << "id = " << id << " &id = " << &id << endl;
}



int main()
{	
	bar1();
	return  0;
}

那么考虑下面的代码,它其实不能编译通过,为什么呢?重复声明/定义!!!现在,引入可见性和声明的区别是否更加清晰了呢?

// namespace.cpp
#include <iostream>
using namespace std;

namespace Department_X {
	static int id = 99;
	void fool(void)
	{
		cout << "departmentX" << endl;
	}
}


void bar1(void)
{
	using Department_X::id;
	cout << "bar1 ";
	cout << "id = " << id << " &id = " << &id << endl;
	
	int id = 299;
	//cout << "id = " << id << " &id = "<< &id <<  endl;
}



int main()
{	
	bar1();
	return  0;
}

1.4 名字空间分类

C++语法规定:
全局或者全局类型统一位于匿名空间
用户通过 namespace 定义有名空间的变量/类型
参考如下代码

#include <iostream>
using namespace std;

namespace SpecName
{
   void foo()
   {
   	cout << "User Namespace::foo" << endl;
   }

};

void foo()
{
   cout << "Ni Ming namespace" << endl;
}
int main()
{
   //using namespace SpecName;
   SpecName::foo();// 有名空间的函数访问
   ::foo(); //全局/匿名空间的访问
   return 0;
}

1.5 namespace 实现机制

我将尝试说明namespace 在C++语言层面的实现机制

// file1 namespace_02.h
#ifndef __NAMESPACE_02__H
#define  __NAMESPACE_02__H
namespace Department_X {
	extern int id;
	void fool(void);
};

namespace Department_Y {
	extern int id;
	void fool(void);
};
#endif // __NAMESPACE_02__H
/****************************************/
//file2 namespace_02.cpp
#include <iostream>

namespace Department_X {
	 int id = 99;
	void fool(void)
	{
		std::cout << "departmentX id = " << id << std::endl;
	}
}

namespace Department_Y {
	 int id = 88;
	void fool(void)
	{
		std::cout << "departmentY id =" << id << std::endl;
	}
}
/***************************/
//file3 main.cpp
#include <iostream>
#include "namespace_02.h"
void show_dep1(void)
{
	using namespace Department_X;
	fool();
	std::cout << id;
}
void show_dep2(void)
{
	using namespace Department_Y;
	fool();
	std::cout <<id;
}


int main()
{
	show_dep1();
	show_dep2();
	return 0;
}

将上面的三个文件一起编译 连接生成可执行文件 a.out
在ubuntu 系统中,使用GNU提供的工具集
nm a.out
你会看到符号表有这几个东西
0000000000601068 D _ZN12Department_X2idE
000000000040093a T _ZN12Department_X4foolEv
000000000060106c D _ZN12Department_Y2idE
0000000000400977 T _ZN12Department_Y4foolEv

名字空间参与了符号修饰,如果读者对编译/链接 有所了解的话,很容易猜测出namespace的原理…有兴趣的话可以翻看一本书《程序员的自我修养》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值