C++中命名空间、缺省参数、函数重载

目录

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. 如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分。