目录
1.命名空间
2.缺省参数
3.函数重载
1.命名空间
在C++中定义命名空间我们需要用到namespace关键字,后面跟上命名空间的名字,结构框架有点类似结构体(如图所示)
上面的代码我一一进行讲解:
1.我们先来说第三行和main函数中的代码意思,第三行代码的意思是展开std库的空间,std是C++的一个基础库,我们为什么要展开它呢?包了iostream文件难道不行吗?这就要涉及到编译C++程序时编译器的搜索方式了,编译器默认是从局部空间和全局空间来进行搜索,而我们的cout和endl虽然在iostream文件里,但它不在编译器的默认搜索范围之内,所以想使用cout和endl我们有两种方式:
第一种就是上述展开std库的方法;
第二种我们可以指定到对应的空间域进行调用(如图所示)
这是一种方法,但是这样写太麻烦了,所以在一般的联系中我们不会写到太多的代码,这个时候我们就可以将std库展开,展开就相当于是全局域,就在我们编译器的默认搜索范围之内了。
::就是我们的域作用限制符,前面跟上空间名称就可以指定到相应的位置。
2.接下来我们来了解命名空间域,它就相当于划分了一块地盘,里面住着各种成员,比如张三家有一只羊,李四家也有一只羊,拿谁家的羊有地址就行,张三家的羊跟李四家的也没有关系。
所以在C语言中同一个变量名不能定义两次,但在C++中就可以。
2.缺省参数
缺省参数是声明或定义函数时为函数的参数指定一个缺省值,在调用该函数时如果没有指定实参则采用该缺省值,有则使用实参。
如图所示,缺省参数使C++在调用函数的时候比C更加灵活。
缺省参数主要分为两种:
1.全缺省参数
顾名思义,全缺省参数就是给每一个参数都设置一个缺省值;
2.半缺省参数
半缺省参数就是不全部设置缺省值的情况。
注意:
1.半缺省参数的设置必须从右往左依次设置,不能间隔着给。
2.函数的声明与定义如果分开写的话不能同时写缺省参数,缺省参数要写在声明中。
如上图,我们想写的是同一个函数,但是缺省值不一样,这个时候我们如果不传实参,编译器该选哪个值?所以为了避免这种情况,就规定了声明和定义不能同时写缺省值,那么为什么要写在声明中呢?这是因为我们测试时是会包含a.h头文件的,编译器在预处理阶段会将头文件展开,相当于把头文件的内容复制到测试文件中,在编译阶段检测到是有这么个函数声明,所以不会报错。
3.缺省参数必须是常量或全局变量。
4.C语言不支持缺省参数。
3.函数重载
自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词的真正含义,即该词被重载了。
比如:以前有一个笑话,中国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个是男足。前者是“谁也赢不了!”,后者是“谁也赢不了!”。
3.1函数重载的概念
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数或类型或类型顺序不同),常用来处理功能类似数据类型不同的问题。(如下图所示)
#include<iostream> using namespace std; // 1、参数类型不同 int Add(int left, int right) { cout << "int Add(int left, int right)" << endl; return left + right; } double Add(double left, double right) { cout << "double Add(double left, double right)" << endl; return left + right; } // 2、参数个数不同 void f() { cout << "f()" << endl; } void f(int a) { cout << "f(int a)" << endl; } // 3、参数类型顺序不同 void f(int a, char b) { cout << "f(int a,char b)" << endl; } void f(char b, int a) { cout << "f(char b, int a)" << endl; } int main() { Add(10, 20); Add(10.1, 20.2); f(); f(10); f(10, 'a'); f('a', 10); return 0; }
5.2C++支持函数重载的原理
1. 实际项目通常是由多个头文件和多个源文件构成,而通过C语言阶段学习的编译链接,我们可以知道,【当前a.cpp中调用了b.cpp中定义的Add函数时】,编译后链接前,a.o的目标
文件中没有Add的函数地址,因为Add是在b.cpp中定义的,所以Add的地址在b.o中。那么
怎么办呢?
2. 所以链接阶段就是专门处理这种问题,链接器看到a.o调用Add,但是没有Add的地址,就
会到b.o的符号表中找Add的地址,然后链接到一起。
3. 那么链接时,面对Add函数,链接接器会使用哪个名字去找呢?这里每个编译器都有自己的函数名修饰规则。
4. 由于Windows下vs的修饰规则过于复杂,而Linux下g++的修饰规则简单易懂,下面我们使
用了g++演示了这个修饰后的名字。
5. 通过下面我们可以看出gcc的函数修饰后名字不变。而g++的函数修饰后变成【_Z+函数长度+函数名+类型首字母】。我们在Linux中写了Add和Func两个函数,接下来我们看看gcc编译后函数的名字
如图所示,还是Add和Func,没有任何变化。
接下来我们来看看C++
我们还是写同样的代码来进行更直观的比较
在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中。
windows下的命名规则:对比Linux会发现,windows下vs编译器对函数名字修饰规则相对复杂难懂,但道理都是类似的,我们就不做细致的研究了。
6. 通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。
7. 如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分。