热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

名字空间的含义及作用

名字空间是为了防止名字污染在标准C++中引入的。它可以将其中定义的名字隐藏起来,不同的名字空间中可以有相同的名字而互不干扰,使用时用域操作符(::)来引用。namespace名字{

名字空间是为了防止名字污染在标准 C++ 中引入的。
它可以将其中定义的名字隐藏起来,不同的名字空间中可以有相同的名字而互不干扰,使用时用域操作符(::)来引用。
namespace 名字
{
   定义的数据;
   定义的函数;
   也可以是定义的类。。。。。。


}

在应用的时候 使用这些数据和函数名称太麻烦
给定义在同一德的名字空间内
不用繁琐的去重新书写和定义
用名字空间就可以了
我觉得有点像类  又有点像 头文件 

使用方法有以下三种:
1> using namespace sdm;
然后你就可以使用变量temp:
temp=9;
还可以使用sdm中的其他每一个成员。
2>using sdm::temp;
在这个文件中只能使用sdm中的temp这个变量。
3>你在使用时直接使用sdm::temp:
cout<使用其它的成员也这样调用。

 
Top
 
 回复人: oyxiaoyu0(小雨仔) ( ) 信誉:100  2002-08-19 11:07:15Z  得分:0 
 
 
?
可以参考以下资料!


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


条款28: 划分全局名字空间

全局空间最大的问题在于它本身仅有一个。在大的软件项目中,经常会有不少人把他们定义的名字都放在这个单一的空间中,从而不可避免地导致名字冲突。例如,假设library1.h定义了一些常量,其中包括:

const double lib_version = 1.204;

类似的,library2.h也定义了:

const int lib_version = 3;

很显然,如果某个程序想同时包含library1.h和library2.h就会有问题。对于这类问题,你除了嘴里骂几句,或给作者发报复性邮件,或自己编辑头文件来消除名字冲突外,也没其它什么办法。

但是,作为程序员,你可以尽力使自己写的程序库不给别人带来这些问题。例如,可以预先想一些不大可能造成冲突的某种前缀,加在每个全局符号前。当然得承认,这样组合起来的标识符看起来不是那么令人舒服。

另一个比较好的方法是使用c++ namespace。namespace本质上和使用前缀的方法一样,只不过避免了别人总是看到前缀而已。所以,不要这么做:

const double sdmbook_version = 2.0;      // 在这个程序库中,
                                         // 每个符号以"sdm"开头
class sdmhandle { ... };                

sdmhandle& sdmgethandle();             // 为什么函数要这样声明?
                                       // 参见条款47

而要这么做:

namespace sdm {
  const double book_version = 2.0;
  class handle { ... };
  handle& gethandle();
}

用户于是可以通过三种方法来访问这一名字空间里的符号:将名字空间中的所有符号全部引入到某一用户空间;将部分符号引入到某一用户空间;或通过修饰符显式地一次性使用某个符号:

void f1()
{
  using namespace sdm;           // 使得sdm中的所有符号不用加
                                 // 修饰符就可以使用

  cout <  ...

  handle h = gethandle();        // handle解释为sdm::handle,
                                 // gethandle解释为sdm::gethandle
  ...                           

}

void f2()
{
  using sdm::book_version;        // 使得仅book_version不用加
                                 // 修饰符就可以使用

  cout <                                  // sdm::book_version
  ...

  handle h = gethandle();         // 错误! handle和gethandle
                                  // 都没有引入到本空间
  ...                            

}

void f3()
{
  cout <                                  // 在本语句有效
  ...                            

  double d = book_version;        // 错误! book_version
                                  // 不在本空间

  handle h = gethandle();         // 错误! handle和gethandle
                                  // 都没有引入到本空间
  ...                           

}

(有些名字空间没有名字。这种没命名的名字空间一般用于限制名字空间内部元素的可见性。详见条款m31。)

名字空间带来的最大的好处之一在于:潜在的二义不会造成错误(参见条款26)。所以,从多个不同的名字空间引入同一个符号名不会造成冲突(假如确实真的从不使用这个符号的话)。例如,除了名字空间sdm外,假如还要用到下面这个名字空间:

namespace acmewindowsystem {

  ...

  typedef int handle;

  ...

}

只要不引用符号handle,使用sdm和acmewindowsystem时就不会有冲突。假如真的要引用,可以明确地指明是哪个名字空间的handle:

void f()
{
  using namespace sdm;                 // 引入sdm里的所有符号
  using namespace acmewindowsystem;    // 引入acme里的所有符号

  ...                                  // 自由地引用sdm
                                       // 和acme里除handle之外
                                       // 的其它符号

  handle h;                            // 错误! 哪个handle?

  sdm::handle h1;                      // 正确, 没有二义

  acmewindowsystem::handle h2;         // 也没有二义

  ...

}

假如用常规的基于头文件的方法来做,只是简单地包含sdm.h和acme.h,这样的话,由于handle有多个定义,编译将不能通过。

名字空间的概念加入到c++标准的时间相对较晚,所以有些人会认为它不太重要,可有可无。但这种想法是错误的,因为c++标准库(参见条款49)里几乎所有的东西都存在于名字空间std之中。这可能令你不以为然,但它却以一种直接的方式影响到你:这就是为什么c++提供了那些看起来很有趣的、没有扩展名的头文件,如, 等。详细介绍参见条款49。

由于名字空间的概念引入的时间相对较晚,有些编译器可能不支持。就算是这样,那也没理由污染全局名字空间,因为可以用struct来近似实现namespace。可以这样做:先创建一个结构用以保存全局符号名,然后将这些全局符号名作为静态成员放入结构中:

// 用于模拟名字空间的一个结构的定义
struct sdm {
  static const double book_version;
  class handle { ... };
  static handle& gethandle();
};

const double sdm::book_version = 2.0;      // 静态成员的定义

现在,如果有人想访问这些全局符号名,只用简单地在它们前面加上结构名作为前缀:

void f()
{
  cout <

  ...

  sdm::handle h = sdm::gethandle();

  ...
}

但是,如果全局范围内实际上没有名字冲突,用户就会觉得加修饰符麻烦而多余。幸运的是,还是有办法来让用户选择使用它们或忽略它们。

对于类型名,可以用类型定义(typedef)来显式地去掉空间引用。例如,假设结构s(模拟的名字空间)内有个类型名t,可以这样用typedef来使得t成为s::t的同义词:

typedef sdm::handle handle;

对于结构中的每个(静态)对象x,可以提供一个(全局)引用x,并初始化为s::x:

const double& book_version = sdm::book_version;

老实说,如果读了条款47,你就会不喜欢定义一个象book_version这样的非局部静态对象。(你就会用条款47中所介绍的函数来取代这样的对象)

处理函数的方法和处理对象一样,但要注意,即使定义函数的引用是合法的,但代码的维护者会更喜欢你使用函数指针:

sdm::handle& (* const gethandle)() =      // gethandle是指向sdm::gethandle
  sdm::gethandle;                         // 的const 指针 (见条款21)

注意gethandle是一个常指针。因为你当然不想让你的用户将它指向别的什么东西,而不是sdm::gethandle,对不对?

(如果真想知道怎么定义一个函数的引用,看看下面:

sdm::handle& (&gethandle)() =      // gethandle是指向
  sdm::gethandle;                  // sdm::gethandle的引用

我个人认为这样的做法也很好,但你可能以前从没见到过。除了初始化的方式外,函数的引用和函数的常指针在行为上完全相同,只是函数指针更易于理解。)

有了上面的类型定义和引用,那些不会遭遇全局名字冲突的用户就会使用没有修饰符的类型和对象名;相反,那些有全局名字冲突的用户就会忽略类型和引用的定义,代之以带修饰符的符号名。还要注意的是,不是所有用户都想使用这种简写名,所以要把类型定义和引用放在一个单独的头文件中,不要把它和(模拟namespace的)结构的定义混在一起。

struct是namespace的很好的近似,但实际上还是相差很远。它在很多方面很欠缺,其中很明显的一点是对运算符的处理。如果运算符被定义为结构的静态成员,它就只能通过函数调用来使用,而不能象常规的运算符所设计的那样,可以通过自然的中缀语法来使用:

// 定义一个模拟名字空间的结构,结构内部包含widgets的类型
// 和函数。widgets对象支持operator+进行加法运算
struct widgets {
  class widget { ... };


  // 参见条款21:为什么返回const
  static const widget operator+(const widget& lhs,
                                const widget& rhs);

  ...

};

// 为上面所述的widge和operator+
// 建立全局(无修饰符的)名称

typedef widgets::widget widget;


const widget (* const operator+)(const widget&,        // 错误!
                                 const widget&);       // operator+不能是指针名
 

widget w1, w2, sum;

sum = w1 + w2;                           // 错误! 本空间没有声明
                                         // 参数为widgets 的operator+

sum = widgets::operator+(w1, w2);        // 合法, 但不是
                                         // "自然"的语法

正因为这些限制,所以一旦编译器支持,就要尽早使用真正的名字空间。

 


推荐阅读
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 在尝试对 QQmlPropertyMap 类进行测试驱动开发时,发现其派生类中无法正常调用槽函数或 Q_INVOKABLE 方法。这可能是由于 QQmlPropertyMap 的内部实现机制导致的,需要进一步研究以找到解决方案。 ... [详细]
  • 在C++程序中,文档A的每一行包含一个结构体数据,其中某些字段可能包含不同数量的数字。需要将这些结构体数据逐行读取并存储到向量中,随后不仅在控制台上显示,还要输出到新创建的文档B中。希望得到指导,感谢! ... [详细]
  • 字符串学习时间:1.5W(“W”周,下同)知识点checkliststrlen()函数的返回值是什么类型的?字 ... [详细]
  • 在分析Android的Audio系统时,我们对mpAudioPolicy->get_input进行了详细探讨,发现其背后涉及的机制相当复杂。本文将详细介绍这一过程及其背后的实现细节。 ... [详细]
  • 在《Cocos2d-x学习笔记:基础概念解析与内存管理机制深入探讨》中,详细介绍了Cocos2d-x的基础概念,并深入分析了其内存管理机制。特别是针对Boost库引入的智能指针管理方法进行了详细的讲解,例如在处理鱼的运动过程中,可以通过编写自定义函数来动态计算角度变化,利用CallFunc回调机制实现高效的游戏逻辑控制。此外,文章还探讨了如何通过智能指针优化资源管理和避免内存泄漏,为开发者提供了实用的编程技巧和最佳实践。 ... [详细]
  • 本文详细解析了Java类加载系统的父子委托机制。在Java程序中,.java源代码文件编译后会生成对应的.class字节码文件,这些字节码文件需要通过类加载器(ClassLoader)进行加载。ClassLoader采用双亲委派模型,确保类的加载过程既高效又安全,避免了类的重复加载和潜在的安全风险。该机制在Java虚拟机中扮演着至关重要的角色,确保了类加载的一致性和可靠性。 ... [详细]
  • Spring – Bean Life Cycle
    Spring – Bean Life Cycle ... [详细]
  • 单片机入门指南:基础理论与实践
    本文介绍了单片机的基础知识及其应用。单片机是一种将微处理器(类似于CPU)、存储器(类似硬盘和内存)以及多种输入输出接口集成在一块硅片上的微型计算机系统。通过详细解析其内部结构和功能,帮助初学者快速掌握单片机的基本原理和实际操作方法。 ... [详细]
  • 类加载机制是Java虚拟机运行时的重要组成部分。本文深入解析了类加载过程的第二阶段,详细阐述了从类被加载到虚拟机内存开始,直至其从内存中卸载的整个生命周期。这一过程中,类经历了加载(Loading)、验证(Verification)等多个关键步骤。通过具体的实例和代码示例,本文探讨了每个阶段的具体操作和潜在问题,帮助读者全面理解类加载机制的内部运作。 ... [详细]
  • Unity与MySQL连接过程中出现的新挑战及解决方案探析 ... [详细]
  • Android 构建基础流程详解
    Android 构建基础流程详解 ... [详细]
  • 全面解析JavaScript代码注释技巧与标准规范
    在Web前端开发中,JavaScript代码的可读性和维护性至关重要。本文将详细介绍如何有效地使用注释来提高代码的可读性,并探讨JavaScript代码注释的最佳实践和标准规范。通过合理的注释,开发者可以更好地理解和维护复杂的代码逻辑,提升团队协作效率。 ... [详细]
  • 本文详细解析了 Android 系统启动过程中的核心文件 `init.c`,探讨了其在系统初始化阶段的关键作用。通过对 `init.c` 的源代码进行深入分析,揭示了其如何管理进程、解析配置文件以及执行系统启动脚本。此外,文章还介绍了 `init` 进程的生命周期及其与内核的交互方式,为开发者提供了深入了解 Android 启动机制的宝贵资料。 ... [详细]
  • 深入解析Android 4.4中的Fence机制及其应用
    在Android 4.4中,Fence机制是处理缓冲区交换和同步问题的关键技术。该机制广泛应用于生产者-消费者模式中,确保了不同组件之间高效、安全的数据传输。通过深入解析Fence机制的工作原理和应用场景,本文探讨了其在系统性能优化和资源管理中的重要作用。 ... [详细]
author-avatar
mobiledu2502911403
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有