目录
解释一下为什么C语言不支持函数的重载而C++支持函数的重载。
1.命名空间 namespace
当我们用C语言写程序的时候,我们知道变量名不能和库里面的函数名相同,以及变量的名字不能相同。
但是如果我们以后去工作了,在公司完成一个项目的话,我们会进行分工合作,如果我们同事之间用了相同的变量名,就会造成冲突了。为了解决C语言的这个不足。C++设计了命名空间 namespace 这个关键字。
如何使用? 关键字 +命名空间的名字+大括号
如 namespace gwh
{
int a;
int c;
}
注意namespace的作用是隔离,那么如何查找这个被你定义的隔离的数呢?
用你定义的名字(gwh)+::+变量名
即 gwh::a可以访问到我定义的命名空间里面的a
可以看到确实访问成功了 ,而且我可以随意定义变量名不用考虑和别人重名和库函数名。
而且命名空间是可以嵌套的。访问嵌套内部就是一层一层的去访问
从上图我们可以看到,命名空间是可以多次定义的,运行代码的时候编译器会把它们合成到一起去的。
我们现阶段学习只需要写标准命名空间即可。
using namespace std;
2.函数形式参数的缺省
什么叫做函数形参的缺省呢?其实就是给函数的形参赋一个初始值,如果不传这个形参就默认为这个初始值,如果传入参数就会修改这个初始值。其实就是函数定义的时候给形参的一个默认值
分类:
全缺省:形参全部缺省,赋予初始值
半缺省:形参部分缺省,注意不是一半缺省哦。
C语言我们知道 函数的形参不能被定义的时候赋值,但是C++可以。
下面是全省缺
半省缺:
需要注意的是半省缺的开始是从右往左的,也就是从形参的最右开始省缺。不能从形参的左边开始。
省缺的方式,再函数的声明和定义的其中一个省缺就行了注意不能在定义和声明同时省缺。但是推荐在声明省缺,因为我们打出来这个函数名的时候会显示形参。
这样可以提醒我们函数的省缺了什么。
3.函数的重载
C语言中我们知道函数的名字不能相同,否则编译不通过。
但是C++的函数名可以相同,只是要求参数不同。
这个参数不同包括了:参数的个数,顺序,类型。这三个条件有一个满足就可以定义相同名字的函数。而这些相同名字的函数,往往是处理同一类问题的函数。知识传入的参数不同。
这样我们得到了函数重载的定义:函数名相同 参数不同的函数(参数个数,顺序,参数类型)
注意 :函数的返回值相同与否与重载无关。只需要关系参数就行了。
解释一下为什么C语言不支持函数的重载而C++支持函数的重载。
首先我们要明白写完一个代码它的运行过程。。
①预处理:这部分包括了 展开头文件 宏替换 条件编译 去掉注释 其实主要是处理以#为开头的代码。
.c文件转化为.i文件
②编译:检查语法,生成汇编代码。(通常编译错误就是语法出了问题)
.i 文件转化为.s文件,形成汇编文件
③汇编:汇编代码转换成二进制的机器码
.s文件转换为.o文件
④链接:找到函数的地址,把函数之间链接在一起。.o文件转化为可执行文件。
(.o文件里面的其实就是CPU可以识别的二进制序列)
C语言不支持重载的原因是:
C语言在第二部编译的时候只是简单的识别函数,只根据函数的名把它记录在汇编语言func.o的符号表中中,而不看它的参数。但是这时候就会有矛盾,怎么在.o中会有一些相同名的函数呢?此时会报错,而且到后面的链接调用的时候C语言是不看参数的,后面调用的时候也会带来致命的麻烦,我到底该调用哪一个函数呢?他们的名字都相同。这就是C语言不能使用函数重载的原因。
C++支持函数重载的原因
C++编译的时候不仅仅识别的是函数名(而是还有函数名修饰规则),也把函数的参数识别了,由于重载函数的参数不同,就造成了C++识别重载函数为不同的函数。在Linux中 如 Fun(int,a,int*p)被识别为 _Z3FuniPi
参数不同就会被识别为不同的函数。这样在后面调用的时候就有了区别了
C++引用 &
什么是引用?引用就是对一个变量起的另一个名字。可以理解为水浒传里面的“李逵”和“黑旋风”。
虽然不是同一个名字,但是是同一个人。 引用也是一样的,只是给一个变量起了一个小名,本质上代表的还是这个变量。这个“小名”和它的“大名”共同享有同一块空间。
需要注意引用并没有新开辟了内存,只是一个对原来的变量的新的名字。
引用的注意事项
1.引用的时候定义要初始化
2.同一个变量a可以被多次引用(就是可以给它多个小名)
3.引用的专一性,一旦引用一个变量,就不能再引用其他变量了。
C++引用的应用
1.作为形式参数或者返回值 会提高性能(在大的对象或者深度拷贝中)
2.可以作为输出型参数和输出型返回值。通俗的说就是需要形参的改变来影响实参。可以用指针也可以用这个引用。因为引用其实就是变量的本身。
引用作为参数的实际例子:
①
可以看到是和传指针一个效果的,都能让形参的改变来影响实参。
指针是通过传入地址。改变地址里面的内容来改变实参的。
而引用直接改变的就是它本身。只不过传入的是它的小名。
②还有一个点就是我们学习单链表尾插的时候,当尾插第一个元素的时候需要把头指针的改变,需要头指针指向一个节点,这时候只传入这个指针是不会让实参指向这个节点的。这时候就需要传指针的地址了。也就是二级指针。二级指针的解引用就是这个头指针。然后让头指针指向第一个节点即可。这个运用了二级指针来解决这个问题。我们也可以用引用来解决。 直接把这个指针它本省传过去。
引用传过去的,你可以理解为实参和形参就是一个东西,不需要拷贝了。
③输出型参数的时候也可以用引用,也可以用指针。例如二叉树的前中后序遍历。需要返回二叉树元素构成的数组的大小。
还有这个输出型参数(表示数组的长度)
可以用 int& returnSize
引用作为返回值:
int& add(int x,int y)
{
return x+y;
}
作为返回值这里有一个很大的问题。
如果是正常的这个
int add(int x,int y)
{
return x+y;
}
那么 return的(x+y)会放在寄存器中,会有一个拷贝。出这个函数的时候函数栈帧销毁。寄存器保存返回的值,然后把这个返回的值给调用它的函数。而如果用引用返回,就有一个问题,那就是引用的返回不需要拷贝,而是把返回值给了一个int &temp=x+y;这个temp实际上就是返回值的别名,本质上还是(x+y)。而x+y可能会随着函数栈帧的销毁而销毁。这就造成了非法访问。如果随着栈帧的销毁里面的内容别清空的话返回值就是一个随机值了。
那么什么时候用这个引用返回呢? 就是返回的东西不随着函数栈帧的销毁的销毁,是这个函数栈帧外面的东西。比如说全局变量,静态区。还有传入的外部参数,不会随着这个函数的栈帧的销毁而销毁,例如
这个可以用引用返回,引用返回的好处是运算快。
传值返回和传引用返回的区别 :就是传引用返回不需要拷贝 ,传值返回需要拷贝
C++常引用
const 就是保护变量不被修改的 只读 ,不能被修改和存储
了解一下权限放大
const int a=10;
int&b=a;
这个错误,权限放大了,因为const是只读,而下一行的int是可读可写
修改为
const int a=10;
const int&b=a;
就可以了
相同权限
int a=10;
const int&b=a;
权限的缩小,也可以。