C++名字空间详解

代码编译运行环境:VS2012+Win32+Debug


1.名字空间的由来

名字空间(namespace)是由标准C++引入的,是一种新的作用域级别。原来C++标识符的作用域分为三级:代码块({…}和函数体)、类域和全局作用域。如今,在类作用域和全局作用域之间,C++标准又添加了名字空间域这一个作用域级别。

命名空间是ANSIC++引入的可以由用户命名的作用域,用来处理程序中常见的同名冲突。

2.名字空间的作用

名字空间的作用主要是为了解决日益严重的名称冲突问题。随着可重用代码的增多,各种不同的代码体系中的标识符之间同名的情况就会显著增多。解决的办法就是将不同的代码库放到不同的名字空间中。

访问一个具体的标识符的时候,可以使用如下形式:space_name::identifier。即用作用域指示符“::”将名字空间的名称和该空间下的标识符连接起来,这要,即使使用同名的标识符,由于它们处于不同的名字空间,也不会发生冲突。

有两种形式的命名空间——有名的和无名的。

定义格式为:

有名的命名空间:
       namespace 命名空间名 {
              声明序列可选
       }
匿名的命名空间:
       namespace {
              声明序列可选
       }

3.名字空间的注意要点

(1)一个名字空间可以在多个头文件或源文件中实现,成为分段定义。如果想在当前文件访问定义在另一个文件中的同名名字空间内的成员变量,需要在当前文件的名字空间内部进行申明。如标准C++库中的所有组件都是在一个被称为std的名字空间中声明和定义的。这些组件当然分散在不同的头文件和源文件中。

(2)名字空间内部可以定义类型、函数、变量等内容,但名字空间不能定义在类和函数的内部。

(3)在一个名字空间中可以自由地访问另一个名字空间的内容,因为名字空间并没有保护级别的限制。

(4)虽然经常可以见到using namespace std;这样的用法,我们也可以用同样的方法将名字空间中的内容一次性“引入”到当前的名字空间中来,但这并不是一个值得推荐的用法。因为这样做的相当于取消了名字空间的定义,使发生名称冲突的机会增多。所以,用using单独引入需要的内容,这样会更有针对性。例如,要使用标准输入对象,只需用using std::cin;就可以了。

(5)不能在名字空间的定义中声明另一个嵌套的子命名空间,只能在命名空间中定义子命名空间。

(6)名字空间的成员,可以在命名空间的内部定义,也可以在名字空间的外部定义,但是要在名字空间进行声明。

命名空间成员的外部定义的格式为:

名字空间名::成员名 ……

(7)名字空间在进行分段定义时,不能定义同名的变量,否则连接出现重定义错误。因为名字空间不同于类,具有外部连接的特性。由于外部连接特性,请不要将名字空间定义在头文件,因为当被不同的源文件包含时,会出现重定义的错误。

结合以上几点,观察如下程序。

//main.cpp
#include <iostream>

namespace myspace1{
    extern int gvar;//内部声明
    extern int otherVar; //另一个文件中同名名字空间中定义
    using std::cout;
    using std::endl;
    class myclass{
    public:
        void print(){
            cout<<"in space1,gvar="<<gvar<<endl;
        }
    };
}

namespace myspace2{
    using std::cout;
    using std::endl;
    int i=5;
    class myclass{
    public:
        void print(){
            cout<<"in space2"<<endl;
        }
    };
    namespace nestedspace{
        void ExternFunc();//内部声明
    }
}

//外部定义
int myspace1::gvar=1;
void myspace2::nestedspace::ExternFunc()
{
    cout<<"in nestedspace"<<endl;
}

int main(int argc,char* argv[])
{
    myspace1::myclass obj1;
    obj1.print();
    myspace2::myclass obj2;
    obj2.print();
    myspace2::nestedspace::ExternFunc();
    std::cout<<myspace1::otherVar<<std::endl;

    getchar();
}

//sp2.cpp
namespace myspace1{
    int otherVar=3;
}

程序输出结果是:

(8)为了避免命名空间的名字与其他的命名空间同名,可以用较长的标识符作为命名空间的名字。但是书写较长的命名空间名时,有些冗余,因此,我们可以在特定的上下文环境中给命名空间起一个相对简单的别名。

参考如下程序。

namespace MyNewlyCreatedSpace{
    void show(){
        std::cout<<"a function within a namespace"<<std::endl;
    }
}

int main(int argc,char* argv[])
{
    namespace sp=MyNewlyCreatedSpace;
    sp::show();
}

4.匿名名字空间

4.1与static关键字的共同作用

匿名名字空间提供了类似在全局函数前加 static 修饰带来的限制作用域的功能。它的这种特性可以被用在struct和class上, 而普通的static却不能。比如,在两个源文件中定义了相同的全局变量(或函数),就会发生重定义的错误。如果将它们声明为全局静态变量(函数)就可以避免重定义错误。在C++中,除了可以使用static关键字避免全局变量(函数)的重定义错误,还可以通过匿名名字空间的方式实现。参考如下代码。

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

namespace{
    double dvar=1.8;
}
void show1(){
    cout<<"dvar:"<<dvar<<endl;
}

int main(int argc,char* argv[])
{
    void show2();
    show1();
    show2();
}

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

double dvar=2.8;
void show2(){
    cout<<"dvar:"<<dvar<<endl;
}

程序输出:

未命名的名字空间中定义的变量(或函数)只在包含该名字空间的文件中可见,但其中的变量的生存期却从程序开始到程序结束。如果有多个文件包含未命名的名字空间,这些名字空间是不相关的,即使这些名字空间中定义了同名的变量(函数),这些标识符也代表不同的对象。

4.2与static的不同

通过匿名名字空间,同样实现了对不同源文件中同名全局变量(函数)的保护,使它们不至于发生冲一定冲突。在这一点上,匿名名字空间和static的作用是相同的。

但是,用static修饰的变量(函数)具有内部连接特性,而具有内部连接特性的变量(函数)是不能用来实例化一个模板的。参考如下程序。

#include <iostream>
using namespace std;

template <char*p> class Example{
public:
    void display(){
        cout<<*p<<endl;
    }
};

static  char c=‘a‘;
int main(int argc,char* argv[])
{

    Example<&c> a; //编译出错
    a.display();
}

此程序无法通过编译,因为静态变量c不具有外部连接特性,因此不是真正的“全局”变量。而类模板的非类型参数要求是编译时常量表达式,或者是指针类型的参数要求指针指向的对象具有外部连接性。具体要求,参见C++标准关于模板非类型参数的要求:

14.3.2 Template non-type arguments [temp.arg.nontype]

1 A template-argument for a non-type, non-template template-parameter shall be one of:

— an integral constant-expression of integral or enumeration type; or

— the name of a non-type template-parameter; or

— the address of an object or function with external linkage, including function templates and function

template-ids but excluding non-static class members, expressed as & id-expression where the & is

optional if the name refers to a function or array, or if the corresponding template-parameter is a reference;

or

— a pointer to member expressed as described in 5.3.1 .

C++11标准文档的下载见C++11标准文档下载,或者到官网下载:ISO相关标准官网

为了实现技能保护全局变量(函数)不受重定义错误的干扰,能够使它们具有外部连接特性的目的,必须使用匿名名字空间机制。同样是上面的这个程序,将char c=’a’;至于匿名空间进行定义,即可通过编译并运行。读者可自行考证。

通过以上程序,可以看出匿名名字空间与static的区别:包含在匿名名字空间中的全局变量(函数)具有外部连接特性,而用static修饰的全局变量具有内部连接特性,不能用来实例化模板的非类型参数。


参考文献

[1] C++高级进阶教程.陈刚.武汉大学出版社

[2]http://zhidao.baidu.com/link?url=1XLWBRwm0DpflKl9wM0DrjDFN1tY_gvl_c6DUpsHKjteRF-_IUCiAfYsXi21glTgFh1cfuwk0dngzz7Px6YJQa

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-05 12:19:47

C++名字空间详解的相关文章

[No000013F]WPF学习之X名称空间详解

原文:[No000013F]WPF学习之X名称空间详解 X名称空间里面的成员(如X:Name,X:Class)都是写给XAML编译器看的.用来引导XAML代码将XAML代码编译为CLR代码. 4.1X名称空间里面到底都有些什么? x名称空间映射的是:http://schemas.microsoft.com/winfx/2006/xaml,望文生义,它包含的类均与解析XAML语言相关,所以亦称之为“XAML名称空间”. 与C#语言一样,XAML也有自己的编译器.XAML语言被解析并编译,最终形成微

【Oracle XE系列之四】创建OracleXE表空间详解

创建OracleXE表空间示例 sqlplus /nolog connect sys as sysdba SQL> create tablespace OPFOCN  datafile 'C:\\oraclexe\\app\\oracle\\oradata\\PF\\opfo.dbf' size 1024m  autoextend on next 1m maxsize 3000m  extent management local  segment space management auto; 表

Oracle 表空间详解

目录 目录 表空间概述 表空间的分类 默认表空间 查看默认的永久表空间 查看默认的TEMP表空间 查看默认的表空间类型 逻辑结构到物理结构的映射 对表空间的操作 查看表空间使用情况 查看数据库拥有的表空间 查看表空间中的数据文件 查看用户拥有的表空间 创建表空间 修改表空间 修改用户的默认和临时表空间 修改表空间的状态 修改表空间的数据文件 删除表空间 用户表空间限额 表空间概述 Oracle的表空间属于Oracle中的存储结构,是一种用于存储数据库对象(如:数据文件)的逻辑空间,是Oracle

java内存空间详解

Java内存分配与管理是Java的核心技术之一,之前我们曾介绍过Java的内存管理与内存泄露以及Java垃圾回收方面的知识,今天我们再次深入Java核心,详细介绍一下Java在内存分配方面的知识.一般Java在内存分配时会涉及到以下区域: ◆寄存器:我们在程序中无法控制 ◆栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中 ◆堆:存放用new产生的数据 ◆静态域:存放在对象中用static定义的静态成员 ◆常量池:存放常量 ◆非RAM存储:硬盘等永久存储空间 Java内存

ORACLE表空间详解

表空间概念 ORACLE数据库被划分成称作为表空间的逻辑区域--形成ORACLE数据库的逻辑结构. 一个ORACLE数据库能够有一个或多个表空间,而一个表空间则对应着一个或多个物理的数据库文件,但一个数据库文件只能与一个表空间相联系.表空间是ORACLE数据库恢复的最小单位,容纳着许多数据库实体,如表.视图.索引.聚簇.回退段和临时段等. 每个ORACLE数据库均有SYSTEM表空间,这是数据库创建时自动创建的,用于存储系统的数据字典表.程序单元.过程.函数.包和触发器等.SYSTEM表空间必须

Oracle 10g创建表空间的完整步骤详解

本文我们主要介绍了Oracle 10g创建表空间的完整步骤,包括表空间的创建与删除.为应用创建用户以及权限的授予等操作,希望能够对您有所帮助. AD:WOT2014:用户标签系统与用户数据化运营培训专场 Oracle 10g数据库中,当在数据库中创建用户时,基于应用性能和管理方面的考虑,最好为不同的用户创建独立的表空间. 那么创建表空间的步骤是怎样实现的呢?本文我们主要就介绍了这一部分内容,接下来就让我们一起来了解一下这部分内容吧. 1.创建表空间 不论是Lnux环境,还是Wndows环境,都要

53 kvm及libvirt、使用virsh管理kvm虚拟机、网络虚拟化技术基础、网络名称空间netns用法详解

01 kvm及libvirt [[email protected] ~]# yum install libvirt libvirt-client python-virtinst virt-manager virt-install -y [[email protected] ~]# yum -y install qemu-kvm [[email protected] ~]# systemctl start libvirtd.service #创建桥 [[email protected] ~]# v

详解希尔伯特空间——图像处理中的数学原理详解23

欢迎关注我的博客专栏"图像处理中的数学原理详解" 全文目录请见 图像处理中的数学原理详解(总纲) http://blog.csdn.net/baimafujinji/article/details/48467225 图像处理中的数学原理详解(已发布的部分链接整理) http://blog.csdn.net/baimafujinji/article/details/48751037 交流学习可加图像处理研究学习QQ群(529549320) 有段时间没继续更新我的"图像处理中的数

【数字图像处理】六.MFC空间几何变换之图像平移、镜像、旋转、缩放详解

本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程<数字图像处理>及课件进行讲解,主要通过MFC单文档视图实现显示BMP图片空间几何变换,包括图像平移.图形旋转.图像反转倒置镜像和图像缩放的知识.同时文章比较详细基础,没有采用GDI+获取矩阵,而是通过读取BMP图片信息头和矩阵像素实现变换,希望该篇文章对你有所帮助,尤其是初学者和学习图像处理的学生. [数字图像处理]一.MFC详解显示BMP格式图片 [数字图像处理]二.MFC单文档分割窗口显示图片 [数字图像处