C++名字空间/C++命名空间

0、序言


名字空间是C++提供的一种解决符号名字冲突的方法。

一个命令空间是一个作用域,在不同名字空间中命名相同的符号代表不同的实体。

通常,利用定义名字空间的办法,可以使模块划分更加方便,减少模块间的相互影响。

1、名字空间的成员


定义在名字空间中的实体称为名字空间的成员。

名字空间内的名字可以被该名字空间内的其他成员直接访问,名字空间外的代码必须指定该名字位于哪个名字空间。

一个名字空间可以包含多种类型的标识符,如下面所列:

变量、常量、函数、结构体/联合体/枚举、类、嵌套名字空间

名字空间成员的引用方法如下:

namespace_name::member_name

2、定义名字空间


(1)、一个名字空间可以在两个地方被定义:在全局范围层次或者是在另一个名字空间中被定义(这样就形成一个嵌套名字空间),不能在函数和类的内部定义。

(2)、名字空间可以是不连续的,他是由所有分离定义的部分的总体构成的。一个名字空间可以分散多个文件中,不同的文件中名字空间的定义也是累积的。

通常将名字空间的声明放到头文件中,实现放到源文件中。可以将不相关的成员放到不同的头文件中。

(3)、命令空间的作用域不能以分号结尾。

3、嵌套名字空间(Nested Namespce)


3.1、普通嵌套名字空间(ordinary nested
namespace)


一个嵌套名字空间就是一个嵌套作用域,其作用域嵌套在包含他的名字空间中。

在外部引用嵌套空间中的成员时,使用下面的形式

包含嵌套空间的名字空间的名字::嵌套空间的名字::嵌套空间的成员

下面举例说明嵌套名字空间定义和使用


#include <iostream>

namespace MyOutNames
{
int iVal1 = 100;
int iVal2 = 200;

namespace MyInnerNames //定义嵌套名字空间
{
int iVal3 = 300;
int iVal4 = 400;
}
}

int main(void)
{
std::cout<<MyOutNames::iVal1<<std::endl;
std::cout<<MyOutNames::iVal2<<std::endl;
std::cout<<MyOutNames::MyInnerNames::iVal3<<std::endl; //使用嵌套名字空间成员
std::cout<<MyOutNames::MyInnerNames::iVal4<<std::endl; //使用嵌套名字空间成员

return 0;

3.2、内联嵌套名字空间(Inline Namespace C++11)


C++11中,新增inline
namespace,指示命名空间中的名称同时是外层命名空间直接包含的名称。这便于命名空间的版本管理,减少冲突。

inline描述符使得内联命名空间中的声明看起来就好像是直接在外围的命名空间中进行声明的一样。(使用inline关键字定义的内联名字空间成为默认名字空间。)
inline描述符由命名空间的设计者放置,即命名空间的作者可以通过放置inline描述符来表示当前最新的命名空间是哪个.


// file V98.hpp:
namespace V98
{
void f(int); // does something
// ...
}

// file V99.hpp:
inline namespace V99
{
void f(int); // does something better than the V98 version
void f(double); // new feature
// ...
}

// file Mine.hpp:
namespace Mine
{
#include "V99.hpp"
#include "V98.hpp"
}

//file example.cpp
#include "Mine.hpp"
using namespace Mine;
// ...
V98::f(1); // old version
V99::f(1); // new version
f(1); //default version

4、全局名字空间(Global Namespce)


定义在全局作用域的名字(在任意类、函数或命名空间外部声明的名字)是定义在全局命名空间中的。
全局命名空间是隐式声明的,存在于每个程序中。在全局作用域定义实体的每个文件将那些名字加到全局命名空间。
可以用作用域操作符引用全局命名空间的成员。因为全局命名空间是隐含的,它没有名字,
所以使用记号如下方法引用全局命名空间的成员。

::member_name

5、匿名名字空间(Unnamed Namespace)


命名空间可以是未命名的,未命名的命名空间在定义时没有给定名字。其定义方法如下:

namespace     //No name
{
//members....
}

未命名的命名空间与其他命名空间不同,未命名的命名空间的定义局部于特定文件,从不跨越多个文本文件。
未命名的命名空间可以在给定文件中不连续,但不能跨越文件,每个文件有自己的未命名的命名空间。
未命名的命名空间用于声明局部于文件的实体。在未命名的命名空间中定义的变量在程序开始时创建,在程序结束之前一直存在。
未命名的命名空间中定义的名字可直接使用,因为没有命名空间名字来限定它们。


#include <iostream>

namespace //unnamed namespace
{
int count = 1;
}
using namespace std;

namespace //unnamed namespace
{
void name_printf(void)
{
cout << "count = " << count << endl;
}
}

int main(void)
{
count = 3; //直接使用
name_printf(); //直接使用

return 0;
}

未命名的命名空间中定义的名字只在包含该命名空间的文件中可见。

如果另一文件包含一个未命名的命名空间,两个命名空间不相关,可以定义相同的名字,而这些定义将引用不同的实体。
未命名的命名空间中成员的名字不能与全局作用域中定义的名字相同。例子如下,函数也是同样的道理。


int i;  // global variable

namespace //unnamed namespace
{
int i;
}

// error: reference to ‘i’ is ambiguous

像其他命名空间一样,未命名的命名空间也可以嵌套在另一命名空间内部。

如果未命名的命名空间是嵌套的,其中的名字按常规方法使用外围命名空间名字访问:


int i; //Global Variable

namespace local
{
namespace //unnamed namespace
{
int i; // ok: i defined in a nested unnamed namespace is distinct from global i
}
}

local::i = 42;

如果头文件定义了未命名的命名空间,那么,在每个包含该头文件的文件中,该命名空间中的名字将定义不同的局部实体。

未命名的命名空间取代文件中的静态声明

在标准 C++
中引入命名空间之前,程序必须将名字声明为static,使它们的作用域约束于一个文件中。
文件中静态声明的方法是从
C 语言继承而来, C++
不赞成文件静态声明,因为这可能在未来版本中不支持。

匿名名字空间提供了类似在全局函数前加
static 修饰带来的限制作用域的功能。

它的这种特性可以被用在struct和class上,
而static却不能不能修饰class和struct这样的结构定义。

所以应该避免文件静态而使用未命名空间代替。

6、名字空间的别名


可以给名字空间起一个别名,别名是已定义的名字空间的可替换的名称。

一个命名空间可以有许多别名,所有别名以及原来的命名空间名字都可以互换使用。

通过下面的形式将别名指定给已定义的名字空间的名字,就可以创建一个名字空间的别名。

namespace 别名 = 已定义的名字空间名字;

下面举例说明名字空间别名的定义和使用


#include <iostream>

namespace MyNames
{
int iVal1 = 100;
int iVal2 = 200;
}

namespace MyAlias = MyNames; //别名定义

int main(void)
{
std::cout<<MyAlias::iVal1<<std::endl; //别名使用
std::cout<<MyAlias::iVal2<<std::endl; //别名使用

return 0;
}

7、using声明 和 using指示


使用using声明 和 using指示
的好处就是可以使用使用名字空间中成员时,不必加上名字空间的作用域。

using std::cout; //using声明

using namespace std; //using指示

7.1、using声明(using declaration)


一个 using
声明一次只引入一个命名空间成员。

using 声明的作用域从 using 声明点开始,直到包含
using 声明的作用域的末尾,名字都是可见的。外部作用域中定义的同名实体被屏蔽。

using
声明可以出现在全局、局部、类的作用域 和 名字空间中。在类作用域中using声明只能引用基类成员。


//using declaration in Global Scope
#include <iostream>
using std::cout;              //using声明
using std::endl;              //using声明

int main(void)
{
  cout<<"Hello World"<<endl;
  return 0;
}


//using declaration in Local Scope
#include <iostream>

void func(void)
{
using std::cout;
using std::endl;

cout << "Using Declarations In Function"<<endl;
}

int main()
{
func();
// cout << "Hello" <<endl; //error: ‘cout’ and ‘endl’ were not declared in this scope
return 0;
}


//using declaration in Class Scope
#include <stdio.h>

class B
{
public:
void f(void) {printf("In B::f()\n");}
void g(void) {printf("In B::g()\n");}
};

class C
{
public:
void g() {printf("In C::g()\n");};
};

class D : public B
{
public:
using B::f; // OK: B is a base of D2
using B::g; // OK: B is a base of D2
// using C::g; // error: C isn‘t a base of D2
};

int main(void)
{
D MyD;
MyD.f();
MyD.g();
}


//using declaration in Namespce
#include <iostream>

namespace MyNames
{
using std::string;
using std::cout;
using std::endl;

string str;

void func(void){cout << "Hello"<<endl;}
}

int main(void)
{
MyNames::func();
return 0;
}

7.2、using指示(using directive)


using 指示使得整个名字空间中的成员都可见。

using
指示可以出现在全局、局部的作用域 和 名字空间中,不会出现在类的作用域中。


//using directive in Global Scope
#include <iostream>
using namespace std;            //using指示

int main(void)
{
  cout<<"Hello World"<<endl;
  return 0;
}


//using directive in Local Scope
#include <iostream>

void func(void)
{
using namespace std;
cout << "Using Declarations In Function"<<endl;
}

int main()
{
func();
// cout << "Hello" <<endl; //error: ‘cout’ and ‘endl’ were not declared in this scope
return 0;
}


//using declaration in Namespce
#include <iostream>

namespace MyNames
{
using namespace std;

string str;
void func(void){cout << "Hello"<<endl;}
}

int main(void)
{
MyNames::func();
// cout<<"Hello"<<endl; //error: ‘cout’ and ‘endl’ were not declared in this scope
return 0;
}

7.3、避免使用using指示


using 指示注入来自一个命名空间的所有名字,这个方法看似简单,但是如果应用程序使用许多库,并且用
using 指示使得这些库中的名字可见,那么,全局命名空间污染问题就重新出现。

相对于依赖于 using
指示,对程序中使用的每个命名空间名字使用using 声明更好,这样做减少注入到命名空间中的名字数目,
using 
声明引起的二义性错误容易发现和修正。

8、综合应用举例


////file : mynames.hpp
#ifndef MYNAMES__HPP_
#define MYNAMES__HPP_

namespace MyNames
{
//Member:Variable
extern int iVal;

//Member:Class
class MyString
{
public:
MyString(const std::string&);
void OutputString(void);
private:
std::string str;
};

//Member:Function
void NormalFunc(void);

//Member:Struct
struct st_Names
{
char ch;
int count;
};

//Member:Union
union un_Names
{
char ch;
int count;
};

//Member:enum
enum en_Names
{
ZERO,
ONE,
TWO
};
}

#endif /* MYNAMES__HPP_ */

//------------------------------------------------------------------------------------------------------------

//file : mynames.cpp
#include <iostream>
#include "mynames.hpp"

namespace MyNames
{
int iVal = 100;

MyString::MyString(const std::string& refstr)
{
str = refstr;
}

void MyString::OutputString(void)
{
std::cout << str << std::endl;
}

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

//-------------------------------------------------------------------------------------------------------------

//file : example.cpp
#include <iostream>
#include "mynames.hpp"

namespace Name = MyNames;

using namespace Name;

int main(void)
{

std::cout<<iVal<<std::endl;
std::cout<<Name::iVal<<std::endl;
std::cout<<MyNames::iVal<<std::endl;

MyNames::MyString mystr("Hello");
mystr.OutputString();
MyNames::NormalFunc();

MyNames::st_Names myst;
myst.count = 0;

MyNames::en_Names myen;
myen = MyNames::ZERO;

MyNames::un_Names myun;
myun.count = 1;

return 0;
}

-------------------------------------------------------------------------------------------------------------------------------------------------------------

参考资料:

http://wenku.baidu.com/link?url=Brv32XQVY8iHIK48zP7-icKvno3cVRPlhb-0OU7jn2qkkvzI9-hYM7JHGl-EOCk731oV0Kf8eGU__nrI5nBY4kegjmVGxwH-ro3bSQ38g4C

http://blog.csdn.net/syhhl007/article/details/4678786

<<C++ Primer 4th>>

http://publib.boulder.ibm.com/infocenter/comphelp/v101v121/index.jsp?topic=/com.ibm.xlcpp101.aix.doc/language_ref/using_declaration_class_members.html

http://msdn.microsoft.com/en-us/library/was37tzw.aspx

http://www.chenlq.net/books/cpp11-faq/c-0-x-faq-chinese-version-inline-namespace.html

时间: 2024-10-14 11:47:26

C++名字空间/C++命名空间的相关文章

C++名字空间详解

代码编译运行环境:VS2012+Win32+Debug 1.名字空间的由来 名字空间(namespace)是由标准C++引入的,是一种新的作用域级别.原来C++标识符的作用域分为三级:代码块({-}和函数体).类域和全局作用域.如今,在类作用域和全局作用域之间,C++标准又添加了名字空间域这一个作用域级别. 命名空间是ANSIC++引入的可以由用户命名的作用域,用来处理程序中常见的同名冲突. 2.名字空间的作用 名字空间的作用主要是为了解决日益严重的名称冲突问题.随着可重用代码的增多,各种不同的

c++名字空间,C与C++字符串的区别,枚举类型

1:命名空间2:C与C++字符串的区别和基本操作3:枚举类型命名空间#include <string> #include <ctype.h> #include <vector> #include <iostream> #include <fstream> // using declarations states our intent to use these names from the namespace std using namespace

C++笔记--名字空间和异常

名字空间 成员函数可以在名字空间的定义里去声明,然后再去采用一种定义方式例如:namespace__name::member_name的方式去定义这个成员函数 1 namespace parser{ 2 double prim(bool); 3 double term(bool); 4 } 5 6 double parser::prim(bool get){/*定义*/} 7 double parser::term(bool get){/*定义,这些定义式定义在命名空间之外的*/} 名字空间中的

ISO/IEC 9899:2011 条款6.2.3——标识符的名字空间

6.2.3 标识符的名字空间 1.如果一个特定标识符的多个声明在一个翻译单元的任意一点可见,那么语法上下文会区分对不同实体的引用.从而,对于标识符各种不同的类别具有独立的名字空间: ——标签名(通过标签声明和使用的语法进行区分): ——结构体.联合体以及枚举的类型名(通过关键字struct.union或enum进行区分): ——结构体或联合体的成员:每个结构体或联合体为其成员具有一个独立的名字空间(通过用于访问成员的.或是->操作符的表达式类型进行区分): ——所有其它标识符称为普通标识符(声明

名字空间和异常

那年是787年!公元?--Monty Python 任何规则都不可能如此一般,以至不能容许任何例外(异常).--Bobert Burton 1.模块化和界面 任何实际程序都是由一些部分组成的.例如,最简单的" Hello, world! "程序也涉及到至少两部分:用户代码要求将Hello, world!打印出来,I/O系统完成打印工作. 当一个模块使用另一个模块时,它并不需要知道有关被用模块的所有东西.理想的情况是,一个模块的大部分细节都不为其使用都所知.为此,我们就需要将一个模块和它

iOS: 学习笔记, Swift名字空间

在Swift中, 名字空间是用class(extension)嵌套来实现的, 以下用一个简单样例来进行展示 // // main.swift // SwiftNameSpace // // Created by yao_yu on 14-8-1. // Copyright (c) 2014年 yao_yu. All rights reserved. // // Swift名字空间使用实例 // import Foundation //定义顶层名字空间 class YY{ } //在YY名字空间中

未命名名字空间

未命名的名字空间 我们或许希望所定义的对象.函数.类类型或其他实体,它只在程序的一小段代码中可见,因为这样可以更进一步地缓解名字空间污染问题,因为我们知道该实体只 被用在很有限的地方,所以可能不想再花费太多努力来保证这个实体有惟一的名字而不会与程序其他地方声明的名字冲突.当我们在一个函数或嵌套块中声明一个对 象时,由该声明引入的名字只在声明它的块中可见,但是,如果程序员想让一个实体被多个函数使用,而又不想让该名字在整个程序中可用 又该怎么办呢? 例如 假设我们想实现一组排序函数,对 double

c++新增的名字空间namespace

其实c也有此名字空间的概念 防止命名冲突,尤其是大型程序里很有用,节省精力,以免出错.可以全部引进,可以引进部分,还可以一个都不用.无所谓. using namespace std;  //标准库的名字都放在std里面 1 #include <iostream> 2 #include <string> 3 using namespace std;//标准库里的东西都可以用了.一劳永逸的方法 4 int main() 5 { 6 cout << "请输入姓名:&

查看 Docker 容器的名字空间

转载请注明 http://blog.csdn.net/yeasy/article/details/41694797 熟悉 Linux 技术的人都知道,容器只是利用名字空间进行隔离的进程而已,Docker 在容器实现上也是利用了 Linux 自身的技术. 有时候,我们需要在宿主机上对容器内进行一些操作,当然,这种绕过 Docker 的操作方式并不推荐. 如果你使用的是比较新的 Docker 版本,会尴尬的发现,直接使用系统命令,会无法访问到容器名字空间. 这里,首先介绍下 ip netns 系列命