在学习基础语法前必须要记住,c++是从c语言的基础上发展出来的,c++的基础语法是解决c语言所存在的一些不足。
命名空间
C++为什么要加入命名空间(namespace)这种语法
C 语言中只有一个全局的命名空间(全局空间),所有函数,结构体等类型,以及可能必要的全局变量,都塞在同一个空间,这对于一个大型的C语言软件项目,给函数和全局变量起名不是一个容易的事情,因为必须考虑有没有可能与其它程序员写的代码冲突,多数的做法是对每个模块的一组函数名加个特定前缀,如HTRequest_setInternal
等。这使得程序员每次调用这些函数时都必须多输出一些字符,虽然使用现在比较优秀的IDE(Integrated Development Environment),不会给程序员的输入带来多少负责,但这些字符看起来还是有些多余。所以C++引入了命名空间(namespace)的概念就是为解决这个问题,用命名空间把一些标识符封装起来,使代码看起来更优雅。命名空间不仅可以用于封装类型(class、struct、Enum
)等,还可以用于封装全局变量、全局函数等,将不同模块的标识符分别封装到不同的命名空间中,从而避免标识符的冲突。虽然在命名时添加前缀和使用命名空间看起来没太大区别,然而,命名空间与命名前缀是有本质不同的,设计思想上的不同。相同的前缀只是个表象, 而命名空间的前缀在具体使用中是可以被简化或省略。
后现代大多数语言都有的模块(module)或包(package)的一个作用也能 解决命名冲突,但更主要的作用是从项目整体宏观上抽象出模块的分组与组织。
命名空间的语法规则
创建命名空间,需要使用到namespace
关键字,后面跟命名空间的名字,然后接一对{}
即可,{}
中即为命名空间的成员。
-
命名空间中可以定义变量/函数/类型。
-
命名空间可以嵌套。
-
同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
-
在函数中不能定义命名空间。
-
命名空间的名字本身也需要一个合法的标识符,不能与它所在的命名空间内的其他标识 符重名。
-
命名空间的大括号后面不需要有分号,当然有分号也不会错,只当是空语句。这与类定义后面必须有分号不同。
namespace
后面的{}
可认为与if
或for
类似, 代表一个词法范围,并不是像class
定义什么实体。 -
命名空间限定符
::
前面一般是某个命名空间的名字,而全局空间没有名字,所以直接以::
开头。但在不会出现名字隐藏的情况下,全局空间的::
前缀可省略。 -
main
函数不能放在命名空间中。或者说在默认情况下,C 程序的入口是全局空间的 那个main
函数,当然也可以从中调用其他自定义命名空间内的main
函数。
如何使用自定义命名空间中的函数或变量,最一般的方法是加命名空间名称及作用域限定符,但这种方法从表面上看并没有比纯C语言命名时添加前缀便捷多少,所以C++又添加了using
关键字,可以使用using
关键字可以将命名空间某个标识符引入,也可以将命名空间中的全部标识符引入,但在使用时要注意没有同名的局部变量或全局变量,如果有同名的局部变量则局部优先,如果有同名的全局变量则会触发“…是不明确的符号”。总而言之,要想使用自定义命名空间中的定义函数或变量等标识符就要先导入命名空间。
命名空间本质上是定义的一个域,标识符的定义都在域中。
编译器是如何确定标识符
程序执行过程中,尤其是在在项目中有多处定义了相同的标识符的情况下,编译器是如何确定函数中标识符所指的究竟是哪一个标识符的呢,对于一个函数中一个标识符(此处所指的标识符现在主要指的是变量、函数),编译器确定标识符实际上就是找到该标识符的定义,所以现在的问题就是编译器将如何查找到标识符的定义呢,编译器按照一定的查找顺序在不同的域中对标识符的定义进行查找,而编译器对标识符(变量、函数等)的默认查找顺序是先在当前局部域查找,再同时到全局域和导入的命名空间域中查找,如果都没有找到,那么编译器就会报一个“…是未声明的标识符”的错误。必须要导入自定义的命名空间,才会到命名空间中去查找,导入命名空间可以使用using
关键字,也可以使用自定义命名空间的名称::标识符
,但一定要导入命名空间。
同一个域中不能定义同名的变量,不同的域中才可以定义同名的变量