C++Primer笔记(2)::命名空间

大型程序一般都是分为多个模块,由多人协作来进行开发的,其中还不可避免的会用到库。而各个模块代码以及库中会定义大量变量,而大量变量的命名,不可避免的会遇见“重名”的问题。“重名”的情况我们称之为命名空间污染。就像你的同学重名了(这也是没有办法的事),比如同班有两个李明(此名重名率极高),这个时候当你们提到其中某一个时,聆听者就搞不懂到底说的是哪个李明了,这个时候就出现了命名空间污染。而这个时候,命名空间就派上用场了,而所谓的命名空间事实上就相当于给作用域起了一个名字,然后你可以在这个作用域中进行各种声明和定义。命名空间的定义如下:

1 namespace my_namespace {    //关键字namespace   命名空间名字
2     int my_test;            //      各种声明和定义
3     namespace son_namespace { /*....*/ } //嵌套命名空间
4 };

只要是能在全局作用域中的声明就能放在命名空间中,包括:类,变量(及其初始化),函数(及其定义)、模板和其他命名空间。

命名空间可以是不连续的。我们可以打开一个已经定义过的命名空间,并在其中添加新的声明与定义。

namespace my_namespace {
    int my_index;              //打开一个已经定义过的命名空间
}//注意此处没有分号!!!

值得注意的是,通常情况下不要将#include <***>放在命名空间中,这样的话等于我们试图将头文件中的命名空间嵌套在我们定义的命名空间中,程序普遍会出错,所以建议避免此种情况的发生。

命名空间的成员在命名空间中可以正常使用,而在命名空间外则需要加上前缀。就比如两个李明一个家是山西太原的,另一个家是陕西西安的,这个时候你就可以说:陕西西安的那个李明如何如何,这样别人就不会出现搞不清楚对象的情况。

my_namespace::my_test = 5;

但是大型项目中变量何其多,这样每个都加前缀会给巨大的不必要的麻烦。所以C++提供了命名空间别名、using声明以及using指示来解决此问题。

命名空间别名其实与类型别名是一样的,它可以让我们为我们定义的命名空间设定一个短的多的同义词,这样可以减轻一点工作量。就比如说你觉着每次都加说陕西西安觉着累,然后你可以告诉聆听者一声,说:说这个太累,后面我就直接说陕西的李明,这样好点。

namespace my_ns = my_namespace;

命名空间别名也可以指向一个嵌套的空间。

namespace son_ns = my_namespace::son_namespace;

using声明的作用与其他声明一致,一条using声明语句一次只引入命名空间的一个成员,它的有效范围从声明开始到声明所在的作用域结束为止。再回到刚才那个例子,这次在谈话之前就告诉聆听者:我先声明我说的是咱班陕西西安的那个李明,然后在这次谈话中你说李明他自然知道你说的是哪个了。

1 using my_namespace::my_test;
2 int
3 main(void)
4 {
5     my_test = 10;
6 }

using指示则是将命名空间的所有成员都呈现到当前作用域。就比如告诉聆听者:我接下来说的人都是陕西西安的。

1 using my_namespace;
2
3 int
4 main(void)
5 {
6     my_test = 10;
7     my_index = 100;
8 }

我个人建议谨慎使用using指示,因为和using声明不同,我们无法控制成员的可见与否,因为所有的都是可见的,如果两个using指示的命名空间中有同样名称的成员,则又会出现命名空间污染的情况。

模板特例化必须定义在原始模板所属的命名空间。

全局命名空间以隐式的方式声明,全局作用域中的定义也就定义在全局命名空间。

::someone; //表示全局命名空间中的一个成员

内联命名空间(C++11新标准) ,它的特殊之处在于,内联命名空间中的名字可以被外层命名空间直接使用,无需添加前缀。

inline namespace test {
    /*此命名空间即为内联命名空间*/
};

这个特性对于代码版本升级且需保留旧版本代码的情况来说实在是太有用了。

namespace work {
    namespace edition1 {
        /*初始版本代码*/
    };
    inline namespace edition2 {
        /*新版本代码*/
    };
};

当我们更新代码以及新代码出现故障紧急回撤版本时,只需要增删inline即可,只要保证接口不变,则可以实现无缝更换。

未命名的命名空间,是指namespace后没有自己定义的名字的命名空间。

namespace {
    /*这是一个未命名的命名空间*/
};

未命名的命名空间中定义的变量拥有静态的生命周期,它们在第一次使用前创建,知道程序结束时才销毁。

它的作用与C语言中的static一致。

时间: 2024-08-19 13:51:19

C++Primer笔记(2)::命名空间的相关文章

C++ Primer笔记8_动态内存_智能指针

1.动态内存 C++中,动态内存管理是通过一对运算符完成的:new和delete.C语言中通过malloc与free函数来实现先动态内存的分配与释放.C++中new与delete的实现其实会调用malloc与free. new分配: 分配变量空间: int *a = new int; // 不初始化 int *b = new int(10); //初始化为10 string *str = new string(10, ); 分配数组空间: int *arr = new int[10];//分配的

C++ Primer笔记12_运算符重载_递增递减运算符_成员访问运算符

1.递增递减运算符 C++语言并不要求递增递减运算符必须是类的成员.但是因为他们改变的正好是所操作对象的状态,所以建议设定为成员函数. 对于递增与递减运算符来说,有前置与后置两个版本,因此,我们应该为类定义两个版本的递增与递减运算符. 问题来了,程序是如何区分前置和后置呢?因为都是++和-- 为了解决这个问题,后置版本的递增递减运算符接受一个额外的(不被使用)int类型的形参.当我们使用后置运算符时,编译器为这个形参提供一个值为0的实参.这个形参唯一的作用就是区分前置和后置运算符函数. 因为不会

C++ Primer笔记2_四种类型转换_异常机制

1.类型转换 命名的强制类型转换: 有static_cast.dynamic_cast.const_cast.reinterpret_cast static_cast: 编译器隐式执行的任何类型转换都可以由static_cast完成 当一个较大的算术类型赋值给较小的类型时,可以用static_cast进行强制转换. 可以将void*指针转换为某一类型的指针 可以将基类指针强制转换为派生类指针,但是不安全. 无法将const转化为nonconst,这个只有const_cast才可以办得到 举例:

重读C++ Primer笔记

C++ Primer 5E 有符号和无符号 无符号类型和有符号类型混合运算时,有符号数会被提升至无符号类型,如果其值为负责会产生错误. int main() { unsigned int u = 10; int i = -42; std::cout<<u+i<< std::endl; // 4294967264 if sizeof(int)==4 return 0; } 列表初始化 列表初始化过程不允许损失数据类型精度,所以下面代码中的两行无法通过编译 int main() { d

C++ Primer笔记6_STL之泛型算法

1.泛型算法: 大多数算法定义在头文件algorithm中,标准库还在头文件numeric中定义了一组数值泛型算法 只读算法: 举例: find函数用于找出容器中一个特定的值,有三个参数 int val = 10;//val为我们需要查找的值 auto result = find(vec.begin(), vec.end(), val): cout << "The value "<< val << (result == vec.end() ? &qu

C++ Primer笔记13_运算符重载_总结

总结: 1.不能重载的运算符: . 和 .* 和 ?: 和 ::  和 sizeof 和 typeid 2.重载运算符有两种基本选择: 类的成员函数或者友元函数, 建议规则如下: 运算符 建议使用 所有一元运算符 成员函数 = () [] -> 必须是成员函数 += -= /= *= ^= &= != %= >>= <<= , 似乎带等号的都在这里了. 成员函数 所有其它二元运算符, 例如: –,+,*,/ 友元函数 3.前几篇中的实例,现在汇总Person类的程序:

C++ Primer笔记4_类的静态成员_IO库

1.类的静态成员 static成员变量与函数 static成员变量:必须在类外初始化:(const或引用类型变量必须在构造函数初始化列表里初始化) static成员函数: 不依赖于类,相当于类里的全局函数(可以由该类对象调用,也可以 类名::函数名()的形式调用) 不包含this指针,不能声明为const,声明为const表示不会改变对象,而static成员函数存在于任何对象之外. 相当于把访问范围限制在所在的类中!  注意:不能访问类中非static成员变量以及非static成员函数. 注意:

C++ Primer笔记3_默认实参_类初探_名字查找与类的作用域

1.默认函数实参 在C++中,可以为参数指定默认值,C语言是不支持默认参数的,Java也不支持! 默认参数的语法与使用: (1)在函数声明或定义时,直接对参数赋值.这就是默认参数: (2)在函数调用时,省略部分或全部参数.这时可以用默认参数来代替. 注意事项: (1)函数默认值只能赋值一次,或者是在声明中,或者是在定义中,都可以. (2)默认参数定义的顺序为自右到左.即如果一个参数设定了缺省值时,其右边的参数都要有缺省值.比如int f(int a, int b=1,int c=2,int d=

C++ Primer笔记7_STL之关联容器

关联容器 与顺序容器不同,关联容器的元素是按关键字来访问和保存的.而顺序容器中的元素是按他们在容器中的位置来顺序保存的. 关联容器最常见的是map.set.multimap.multiset map的元素以键-值[key-value]对的形式组织:键用作元素在map中的索引,而值则表示所存储和读取的数据. set仅包含一个键,并有效的支持关于某个键是否存在的查询. pair类型 首先介绍下pair,pair定义在utility头文件中,一个pair保存两个数据成员,类似容器,pair是一个用来生