C++学习笔记:命名空间基础
1. 何为命名空间
1.1 什么是命名空间
namespace
,中文就是命名空间,同时这也是C++
语言中的一个关键字。命名空间是C++
引入的一种彻底地、很方便地解决全局变量和函数名冲突的机制。变量分全局变量和局部变量,所谓全局,就是定义在函数之外的,局部变量则一般定义在函数体内部。函数则全部是全局性质的。
C
语言没有命名空间,但是C++
及之后的Java
、Python
等高级语言都有,并且在C++
的基础上有更好的改进。
理解命名空间的关键点有2个:
- 1.命名空间是如何解决名称冲突的
- 2.使用了命名空间后如何合法地访问变量
1.2 C语言是如何解决名称冲突的
首先要知道,名称冲突是一个客观存在。在大型的C语言项目中会有很多C
文件,全局变量和函数都是extern
链接属性,一个项目是一个单体程序,项目中的全局变量和函数理应能互相访问,因此很容易发生名称冲突。
C
语言中解决名称冲突的办法是:
- 1.同一个
C
文件不要太大,由一个人写。 - 2.每个
C
文件(或几个C
文件构成的一个模块)中所有全局变量和函数前加统一的唯一前缀。比如写SD卡模块的函数名都叫sd_func()
,写串口模块的都叫uart_func()
。 - 3.不需要文件外访问的全局变量和函数前面都加
static
,static
修饰全局变量和函数的作用就是将该变量和函数的可见范围从external
到local
,即本文件内可见。
C
语言的这种解决命名冲突的方案是可行的,不然不会有Linux
这样大的项目,并且C++
早期就是这样做的,但这种方法太生硬,没有从语言本身去解决问题,显得不够美观。
1.3 命名空间如何解决问题
为实现命名空间机制,C++
引入了namespace
关键字,定义格式为:
namespace xx{
};
命名空间本质上其实是对全局变量和函数在一定范围内链接属性的更改和控制,尖括号{}
内就是命名空间的范围。一个特定名称的namespace
,比如上面的xx
,一对大括号内部定义的变量、函数、类等均属于该命名空间内。
在命名空间内部互相引用时可以直接使用变量名、函数名等,跨命名空间互相引用时必须同时指定被引用方的命名空间名和变量名、函数名才可以找到,因此其实命名空间看起来就好像是给这个变量名、函数名添加了一种前缀。
1.4 关于语言特性的思考
- 语言特性是语言通过关键字或符号所支持、所引入的一种功能特性,如
namespace
、template
、运算符重载
、面向对象
等。 - 语言特性必定对应解决某种问题,必定在某方面对程序员有帮助,是有了某个问题不好解决,才需要引入一种语言特性或者说机制来解决这个问题。
- 语言特性越多或者设计越复杂,则语言本身就越难使用,但语言就越厉害,
C++
就是这样的一种语言。 - 语言特性体现为某种语法,本质上靠编译工具链提供支持,
C++11/14/17/20
的版本变迁,无非是新增或修正某些细节语言特性。 - 就事论事讨论编程语言,其实难点都在掌握和熟练运用语言特性上。
2.namespace的初级定义和使用
2.1 同一文件内定义namespace
#include<iostream>
using namespace std;
namespace test{
int a;
float b;
void test_func(void){
cout<<"test_func"<<endl;
}
};
2.2 同一文件内使用namespace
namespace
有三种引用方法。
方式一:不做任何声明直接使用,类似于添加前缀,::
叫做作用于解析符,左边是命名空间的名字,右边是该空间内的变量或函数名。这样编译器就会知道你要用的是test
空间中的变量a
以及函数test_func()
。
test::a;
test::test_func();
方式二:通过using
告诉编译器去test
空间中寻找test_func
来使用。
//声明test_func可以到test中找
using test::test_func();
//使用test_func
test_func();
方式三:直接声明命名空间,则该命名空间下的变量函数可以直接使用。
using namespace test;
test_func();
2.3 不同cpp文件间定义和使用namespace
在文件1中定义的变量和函数是可以在另一个文件2中被使用的,关键是如何在文件2中声明。规范的方法应该是同时写一个test1.h,即头文件,在头文件中写入命名空间以及命名空间内的函数声明,在.cpp文件中写函数的实现,然后在调用该函数的源文件中包含该头文件。
test1.h:
#ifndef TEST1_H
#define TEST1_H
namespace test1{
void func_1();
};
#endif
test1.cpp:
#include"test1.hpp"
#include<iostream>
void test1::func_1()
{
std::cout<<"this is test1 func1"<<std::endl;
}
test2.cpp:
#include"test1.hpp"
using namespace test1;
int main(int argc,char**argv)
{
func_1();
return 0;
}
编译命令:
g++ test2.cpp test1.cpp