第十七章:用于大型程序的工具:命名空间
在一个给定的作用域中定义的每个名字,在该作用域中必须是唯一的。对庞大、复杂的应用程序而言,这个很难满足。由独立开发的库构成的复杂程序更有可能遇到名字冲突,因为库倾向于使用全局名字:模板名、类型名或函数名。命名冲突问题被称为:命名空间污染。
命名空间为防止名字冲突,提供了更加可控的机制。命名空间能够划分全局命名空间。一个命名空间是一个作用域,通过在命名空间内定义库中的名字,就可以避免全局名字固有的限制。
命名空间以namespace开始,后接命名空间的名字。如:
namespace aa
{
class Bar
{
public:
Bar(){}
};
class Bar2{};
}
该命名空间定义了两个类。
在定义命名空间的作用域中,命名空间的名字必须是唯一的。命名空间可在全局作用域或其他作用域内部定义,但不能在函数或类内定义。
命名空间不能以分号结束哦。
每个命名空间是一个作用域,在同一个命名空间中,每个名字也同样必须是唯一的。每个名字可以在其他的命名空间中引用,但必须指出名字所属的名字空间。如
aa::Barbar;
每次在使用某一命名空间的成员,都指定命名空间名非常麻烦。可以像std中定义的命名空间那样,使用using声明,来获得对我们经常使用的名字直接访问。如:
using std::cout;
using aa::Bar;
同一命名空间可以在几个部分定义,命名空间由各个部分的总和构成。一个命名空间的分离部分甚至可以分散在多个文件中。
namespacenamespace_name
{
}
该定义既可以定义新的命名空间,也可以添加到现存命名空间。
命名空间可以不连续意味着:可以用分离的接口文件和实现文件构成命名空间。
1:定义类的命名空间成员,以及作为类接口一部分的函数声明与对象声明,可以放在头文件中。使用命名空间成员的文件可以包含这些文件。
2:命名空间成员的定义可以放在单独的源文件中。
如:
//namespace_a.h
namespacenamespace_a
{
class Bar
{
public:
Bar(){}
void something();
};
}
//namespace_a.cpp
#includer“namespace_a.h”
namespacenamespace_a
{
void Bar::dosomething
{
//////
}
void func();
}
在命名空间内部定义的函数,可以使用同一命名空间中定义的名字的简写形式。如:
namespace A
{
Bar bar;//无需写成namespace_a::Bar
bar;
}
上例中的void func()也可以在命名空间的外部定义,但是必须指定该名字所属的命名空间。如:
void A::func()
{
////////////////
}
虽然可以在命名空间定义的外部定义命名空间,但只有包围成员声明的命名空间,可以包含成员的定义。如dosomething函数可以在定义在A作用域中,也可以定义在全局作用域中,但不能定义在不相关的命名空间中。
经过实践证实上述Bar类的成员函数dosomething也可以在名字空间之外定义。要写成void
A::Bar::dosomething(){};
全局命名空间是隐式声明的,没有名字。包括定义在全局作用域的名字,存在每个程序中。在全局作用域定义的每个文件中的名字将被加入到全局名字空间。
可以用作用域操作符引用全局命名空间的成员。如:
::member_name
可以在其他命名空间定义新的命名空间,这成为命名空间的嵌套。嵌套时,外围命名空间中声明的名字被嵌套命名空间中同一个名字的声明所屏蔽。外围命名空间之外的代码只能通过限定名来引用。如
int g;
namespace A
{
namespace B
{
int a;
}
namespace C
{
B::a=20;
::g=39;
}
}
嵌套命名空间的成员的名字,由外围命名空间的名字和嵌套命名空间的名字构成。如需要引用B中的成员则应为:A::B::a;
在使用namespace定义命名空间时,也可以不指定名字。此时命名空间就是未命名的。未命名的空间局部于特定的文件,不跨越多个文本文件。同一个未命名空间的定义也可以是不连续的。
未命名的空间用于声明局部于文件的实体,它内的成员在程序开始时创建,在程序结束前一直存在。
因为没有空间名,所以未命名空间的成员可以直接使用。如果头文件定义了未命名的名字空间,那么,在每个包含该头文件的文件中,该命名空间的名字将定义不同的局部实体。
未命名空间中定义的名字可以在该命名空间所在的作用域找到,也就是说未命名空间好像不存在似的。可以假定所有命名空间的内部都是有未命名的空间组成。如全局命名空间的未命名空间,在全局空间和其内的未命名空间名字不能相同,也就很好理解了。
除了在函数或其他作用域内部,不应该在头文件中使用using声明或using指示。头文件应该只定义作为其接口的一部分的名字。
一个using声明一次只引入一个命名空间成员。using声明引入的名字遵循作用域规则,从using声明点开始,直到包含该using声明的作用域的末尾,名字都是可见的。外部作用域定义的同名实体被屏蔽。
可以使用命名空间别名,将较短的名字与命名空间的名字关联。如
namespace cplusplus_primer;
namespace cpp=cplusplus_primer;
using声明以关键字using
namespace开头,后接命名空间的名字。
它将名字直接放入出现using声明的作用域。而using指示将命名空间成员提升到包含命名空间本身和using指示的最近作用域的效果。
如namespace a
{
int i,j;
}
void f()
{
using namespace a;//将i,j提升到包含namespace
a和f的全局空间中。
cout<<i*j<<endl;
}
此种提升规则可能会导致命名空间的名字会与外围作用域中定义的其他名字冲突。如果在f外的全局作用域定义intj
;此时的using namespace a;将a的成员提升到全局作用域,在f内使用j就会出现歧义的情况。这种冲突是允许的。但是为了使用j必须指明想使用哪个j。使用::j引用全局作用域的变量,使用a::j引用a中的变量。
using指示会注入另一个命名空间的所有名字,如果程序使用很多库,并且使用using指示使得这些库中的名字可见,那么全局名字空间污染的问题就会重新出现。使用using声明是不错的方法。
std::string s;
getline(std::cin,s);
为什么无需使用std::getline就可以使用该函数?它给出了屏蔽命名空间名字规则的一个重要例外:与类本身定义在同一命名空间的函数,在用类类型对象作为实参时是可见的。
当编译器看到getline(std::cin,s)时,它会在当前作用域、包含调用的作用域以及定义cin的类型和string类型的命名空间中查找匹配的函数。
如namespace A
{
class Bar
{
public:
Bar(){};
};
void print(Bar &b){};
}
void func()
{
A::Bar bar;
print(bar);//调用A中的print.因为它与Bar类处于同一命名空间。
}
原来在介绍友元声明时提到,友元可以在类内声明时定义。在类内定义的友元与类具有相同的作用域,因此在类内定义的友元也适用于上述例外的情况
在同一个作用域的函数才有重载。不同作用组仅仅存在函数名屏蔽。
在同一命名空间内,命名空间对函数匹配有两个影响:1:using声明或using指示可以将函数加到候选集合中
using声明声明一个名字,就像在模板那一章介绍的一样,没有办法用using声明来引用特定函数的声明。如using NS::print(int);//错误。必须写成:using
NS::print;如果命名空间内部的print是重载的,则该函数名字的using声明,声明了所有具有该名字的函数。它们被加入了当前作用域,都在当前作用域中可见。
如果使用using声明时,该作用于已存在相同函数名且形参表相同的函数,则会出错。如果函数名相同但形参表不同,那么声明过来的重载函数会与原来的函数构成新的更大的重载集合。
using指示将命名空间的成员提升到外围作用域。如果命名空间函数与命名空间所在的作用域中声明的函数同名,就将命名空间成员加到重载集合中。
命名空间与模板不再介绍。涉及到模板特化与命名空间的关系。P612。
分享到:
相关推荐
C++Primer中文第三版(C++从入门到精通)第一章的读书笔记,主要是C++程序、预处理器指示符、iostream库等的基础知识点读书笔记。
C++ primer plus 第五版的个人学习笔记,仅供大家学习参考。
C++ Primer 是一本经典的C++学习书籍,涵盖了C++的基础知识和高级特性。这篇学习笔记主要涉及了C++编程的一些核心概念,包括程序结构、变量、基本类型、初始化与赋值、可读性、常量与引用、typedef、枚举以及标准库...
第17章通常会关注C++中的特殊工具和技术,比如了运行时类型识别(RTTI)、智能指针、标准库中的其他组件以及C++11的特性等。在这一章节中,读者可以通过习题来加深理解并掌握这些高级特性。习题通常会提供一个实际...
以上是C++ Primer第四版学习笔记中涉及的一些核心知识点。这些知识点涵盖了C++编程的基础语法、数据类型、容器、指针、内存管理以及控制结构等多个方面,对于初学者理解和掌握C++语言具有重要意义。希望这些内容能够...
但是,我可以根据《C++ Primer》第五版的内容结构以及一般C++的学习顺序,为读者提供第12章可能涵盖的知识点,并对C++11标准中的相关概念进行介绍。 第12章通常会涉及C++中的输入输出库(I/O库),这是C++编程中必...
C++primer第五版第二章习题答案.pdf
《C++ Primer Plus第6版中文版》学习笔记(第十章) 红字内容是有疑问或者没把握的。 绿字部分是比较重要,或者经过确认的
11. **命名空间**:命名空间用于解决全局命名冲突问题,使得大型项目中的代码更易于管理和维护。 12. **C++11新特性**:第四版涵盖了C++11标准的新特性,如lambda表达式、右值引用、自动类型推断(auto)、范围for...
《C++ Primer Plus 第六版中文版》的学习笔记聚焦于第七章,主要讲解了C++中的函数,包括函数的分类、无返回值和有返回值的函数、返回值的类型限制、函数原型的重要性和作用,以及ANSI C与C++在函数原型上的差异。...
《C++ Primer》是一本经典的C++学习教程,第五版是该书的最新版本,涵盖了C++11至C++14标准的最新特性。在IT行业中,掌握C++的重要性不言而喻,因此,这本书以及它的习题集被许多程序员和开发者用作学习和提升技能的...
《C++ Primer 第四版》是一本经典的C++学习书籍,涵盖了从基础到高级的各种主题。这份课后习题解答提供了第1至18章的完整答案,旨在帮助读者深入理解书中的概念并提高编程技能。 第一章“快速入门”引导读者进入C++...
《C++ Primer(第4版)》是一本深入学习C++编程语言的经典教材,其课后习题答案提供了丰富的实践练习和问题解析,帮助读者巩固并深化对C++语法、概念的理解。以下将针对各章节的主要知识点进行详细阐述: 1. 第一章...
通过逐章学习和实践《C++ Primer》中的源程序,不仅可以掌握C++的基本语法,还能理解其面向对象和泛型编程的思想,这对于成为一名熟练的C++开发者至关重要。同时,结合Visual Studio 2012这样的集成开发环境,可以更...
C++ Primer Plus第6版第九章讨论了如何管理和编译多个源文件和头文件,下面是对这一主题的详细解释。 首先,C++提供了多种存储类型来控制数据在内存中的生命周期和访问权限。存储持续性决定了变量或对象的生命周期...
6. **模板**:C++的模板是一种泛型编程工具,可以创建通用函数和容器,如vector、list、map等,以适应不同类型的数据。 7. **STL(Standard Template Library)**:C++标准库中的模板容器、算法和迭代器等组件,...
这份笔记以清晰、实用的方式阐述了C++ Primer第四版中的知识点,对于想要踏入或深化C++编程的读者来说,是一份非常有价值的参考资料。 C++ Primer是C++编程领域的一本经典教材,第四版更是结合了现代C++的特性进行...
C++ Primer Plus第六版是学习C++编程语言的经典教材,其第四章主要涵盖了C++的基础语法和编程概念,包括变量、数据类型、运算符、控制结构等核心知识点。这一章的学习对于初学者来说至关重要,因为它奠定了后续深入...
- **名字空间**:C++标准库中的所有元素都定义在名为`std`的名字空间中。要使用这些元素,通常需要通过`using`声明或`std::`前缀来引入。 - `using namespace std;`:这行代码使得`std`名字空间中的所有元素都可以...