在编程中 难免会遇到两个相同函数名、结构体名,当他们命名冲突时,可以让他们在不用的域里,这个域可以称为 命名空间(namespace)
初识命名空间
命名空间 (namespace) 可以帮助我们区分不同库中相同名称的函数, 类, 变量等. 使用了命名空间即定义了上下文. 命名空间就是定义了一个范围.
为了解决 C++ 标准库中的标识符与程序中的全局标识符之间以及不同库中的所有标识符之间的命名冲突. 标准 C++ 库的所有标识符都定义在一个名为 std 的命名空间中. 在程序中用到 C++ 标准库时, 使用 std 作为限定.
命名空间的作用
自定义函数与标准库函数重名
程序中使用的名字与第三方库中名称相同
同一项目不同模块中名字的冲突
命名空间的用法
既然认识了命名空间,直到了命名空间的作用,还有命名空间的用法,来看一个小例子:
这里用到了 ::(域作用限定符) 若你想访问该命名空间内的对象,那么就要加个::。
命名空间名::要访问的对象
这里定义了两个命名空间 名为m1、m2。他们之中都有f 但并不冲突,因为他们在不同的作用域中(实际上命名空间还是全局域中,但是他们互不干扰)
命名空间的名称可以相同(在编译时时会合并),那么相同名字的作用域下,就算同一个作用域,那么他们就不能有同名的变量名、结构体名等等。
命名空间可以嵌套
例如:
在相同的作用域下嵌套了不同的作用域
但是访问时就会很麻烦,如果我们继续嵌套下去 那么最终我们要定义一个结构体,那么不算非常麻烦?
这时就可以用到using 它可以帮助我们引入命名空间 最简单的例子:
这样我们访问std命名空间时,就不用再在作用域这么麻烦了。
那么访问时:
但是不同同时:
因为这两个作用域下的Node时一样的,编译器无法区分 你到底要创建哪个作用域下的Node
这里推荐using namespace你最常用的。
#include
using namespace std;
这里的std就是封C++库的命名空间
例如常用的 cout 是定义在iostream库中 库中定义的名字都在命名空间std中
所以 cout的全称为: std::cout
其实用using namespace std;是有冲突的风险的 建议using常用的,例如cout、cin等等,但是因为方便,所以还是常常用using namespace std;
两种叫法,都是一样的意思 这里叫做缺省函数
缺省函数初识
就是在声明函数的某个参数的时候为之指定一个默认值,在调用该函数的时候如果采用该默认值,你就无须指定该参数。
缺省参数使用主要规则:
若第一个参数有默认值,则后面的参数都必须有默认值。若它没有默认值,它前面的参数有默认值,这就算不符规则的。参数默认值必须是连续的
缺省参数 定义与声明不能同时出现(定义、声明的参数不能同时有默认值)若分.cpp与.h时,尽量声明给缺省,定义不给。
函数重载初识
C++允许在同一范围中声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,也就是说用同一个函数完成不同的功能。 这就是重载函数
重载函数常用来实现功能类似而所处理的数据类型不同的问题
交换函数 需要交换不同类型的类型时,就可以用到函数重载
例如:
同一个函数名,通过传参的类型不同,调用相同函数名不同功能的函数
这里抛出一个问题: 为什么C++支持重载而C语言不支持重载?
这里先了解编译链接的过程
1.预处理——头文件展开,宏替换,条件编译,去掉注释
2.编译——检查语法,生成汇编代码
3.汇编——把汇编代码转换成二进制的机器码
4.链接——找调用函数地址,链接对应上合并到一起。
这里还需要直到 符号表
符号表:过程名表、函数名表、等等 统称符号名表 对于符号表组织、构造和处理方法的好坏直接影响编译系统的运行效率。
符号表的作用:符号表在编译程序工作的过程中不断收集、记录和使用源程序中一些语法符号的类型和特征等相关信息。
编译阶段找函数地址,就在这个阶段,就能体现出C++与C的区别
C++符号表记录函数名的命名规则为:
_Z 函数名长度 函数名 类型首字母
当两个相同的函数名 他们在类型首字母时不一样的,所以编译器能区分他们
C符号表记录函数名的命名规则为:
函数名
这就造成了 两个相同的函数名 编译器无法区分它们
这就说明了在底层的上 C++与C已经做出了区别
静态库是指在我们的应用中,有一些公共代码是需要反复使用,就把这些代码编译为“库”文件;在链接步骤中, 连接器 将从库文件取得所需的 代码 ,复制到生成的 可执行文件 中的这种库
这部分讲解 C++如何调用C的静态库 和 C如何调用C++的静态库
1.如何创建一个静态库?
打开一个项目 选择你想要将此项目改为静态库 (一般都是把栈、队列)改为静态库
这样就创建了一个静态库
2.如何使用一个静态库?
打开一个需要静态库的项目
然后点上一层 直到找到 你 命名的 静态库 的名字 (就是项目名)
我命名的静态库名字为 静态库栈 就点进去 直到找到 栈的声明文件
然后用#include 去引用刚才的这个路径
例如 我的是:
这样就引用了你刚才创建的静态库,但还没完
还是一样 找到刚才的静态库文件 但是这次点击Debug 然后点进去是空的,确定就好,点应用
还是找刚才静态库的文件 点Debug 里面就多出了一个后缀为lib的文件,复制它的名字
然后在最前面复制,然后加个 ; 分割
这样就可以了
可能有些人试过了上面的方法 还是会出错 (除开你的语法错误之外)就是C调用C++,或者C++调用C 没做优化 这些 我待会会讲
3.如何用C++调用C++的静态库?
毕竟是C++调用C++的静态库 只要你的步骤没错 可以直接通过
4.如何用C调用C的静态库?
跟上面一样 只要是语言一样 除开语法错误外 可以直接通过
5.如何用C++调用C的静态库
上面讲过 C++的底层和C已经不一样了,但是C++专业人员考虑到可能会用到C的库,并且C++会兼容C 所以推出了一个关键字 extern 这个关键字能让C++去用C语言的规则去调用C的静态库
具体方法如下:
6.如何用C调用C++的静态库
这里需要用到条件编译
因为C语言没办法支持C++的语法 所以只能到C++这里改动
#ifdef __cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C
#endif
//初始化
EXTERN_C void StackInit(Stack* st);
//入栈
EXTERN_C void StackPush(Stack* st, STDataType x);
//出栈
EXTERN_C void StackPop(Stack* st);
//判空
EXTERN_C bool StackEmpty(Stack* st);
//返回栈顶元素
EXTERN_C STDataType StackTop(Stack* st);
//返回栈中有多少元素
EXTERN_C int StackSize(Stack* st);
//释放
EXTERN_C void StackDestory(Stack* st);
这里的意思是 如果他是C++ 那么就改成C的语法 如果不是 就什么都不做
如果本篇文章对您有帮助,希望能获得您的赞!