缺省参数
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
void Func(int a = 0)
{
cout << a << endl;
}
int main()
{
Func();
Func(10);
return 0;
}
在形参的后面赋值,这个值就叫做缺省参数
可以不传参调用函数,不传参的时候,a的值就是缺省参数0
显示传的时候,a就用传的参数,不用缺省参数
注意:
缺省值必须是常量或全局变量
C语言不支持(编译器不支持)
全缺省
#include <iostream>
using namespace std;
void Func(int a = 10, int b = 20, int c = 30)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl << endl;
}
int main()
{
Func();
Func(1);
Func(1, 2);
Func(1, 2, 3);
return 0;
}
三个缺省参数,变化出四种调用方式
注意:
- 不可以跳跃着传
Func(,2,);
只给第二个传,是错误的
- 如果不传参数,就用缺省值
半缺省
#include <iostream>
using namespace std;
void Func(int a, int b = 20, int c = 30)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl << endl;
}
int main()
{
//Func(); 不支持了
Func(1);
Func(1, 2);
Func(1, 2, 3);
return 0;
}
注意:
- 缺省值只能从右往左给,必须是连续给,这样传参也是连续的。
- 从左往右缺省,传参的时候会有歧义,从右往左缺省不会产生歧义
- 不能间隔着给缺省值
不能声明和定义同时存在
- 函数的声明和定义同时有缺省参数,会报错
因为怕声明和定义分别给不同的缺省参数,这样不知道以谁为准 - 也不能只在定义中给,声明中不给
用这个函数的时候,有可能只包含了声明头文件
这样在另外一个文件用的时候,include ”xxx.h“
如果声明文件里没有缺省参数,就不知道这个函数没传参的时候给多少 - 所以最好的方式就是在函数声明的时候给缺省参数
#pragma once
include <stdio.h>
namaspace cho
{
typedef struct Stack
{
int* a;
int top;
int capacity;
}ST;
void StackInit (ST* ps, int n = 4);
void StackPush (ST* ps, int x);
}
#include "Stack.h"
namespace cho
{
void StackInit (ST* ps, int n = 40)
{
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
void StackPush(ST* ps, int x)
{
//...
}
}
#include <Stack.h>
int main()
{
cho::ST s;
cho::StackInit(&s);
cho::StackPush(&s, 1);
return 0;
}
函数重载
有点像一词多义
一个函数名有多个意义
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。
C语言不支持同名函数
但是我们需要同名函数
参数类型不同
#include <stdio.h>
using namespace std;
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;
}
int main()
{
Add(1, 2);
Add(1.1, 2.2);
return 0;
}
两个数相加,C语言的话这段代码就报错了;C++支持
会调用不同的函数
Add(1, 2.2);
传一个int,一个double会报错
不是因为匹配,int和double是有隐式类型转换的,传参的时候,可以考虑让int转double,也可以让double转int,会出现歧义,这里编译器会报错
参数个数不同
#include <stdio.h>
using namespace std;
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f(int a)" << endl;
}
int main()
{
f();
f(1);
return 0;
}
注意:
- 函数名相同,参数不同(类型不同,个数不同),返回值可同可不同
- 编译器会根据参数的不同去匹配不同的函数
[!NOTE] 返回值不同为什么不可以
两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分
如果返回值不同可以构成重载,调用的时候不知道要调谁
不能明确要调谁,会存在调用歧义
函数顺序不同
也可以归类为类型不同
#include <iostream>
using namespace std;
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()
{
f(10, 'a');
f('a', 10);
return 0;
}
重载和缺省同时存在
如果是
#include <iostream>
using namespace std;
void f()
{
cout << "f()" << endl;
}
void f(int a = 0)
{
cout << "f(int a)" << endl;
}
int main()
{
f();
f(1);
return 0;
}
构成重载
f()没有参数,f(int a = 0)有一个int参数
只看参数类型,不看有没有缺省参数
但是实践的时候会有问题
f()不知道会调谁
不传参数的时候会有二义性
为什么C++支持函数重载
从编译链接的角度来看
#pragma once
#include <iostream>
using namespace std;
void f(int a, char b);
void f(char b, int a);
#include "Func.h"
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;
}
#include "Func.h"
int main()
{
f(10, 'a');
f('a', 10);
return 0;
}
前置知识
程序编译过程:
编译器对多文件进行编译的时候
会进行
1. 预处理
头文件展开/宏替换/条件编译/去掉注释…
其中头文件展开,会将Fun.h拷贝过去
不过只是直接拷贝到文件里
编译器会生成Func.i和Test.i文件
Func.i文件里有Func函数的声明和定义
Test.i文件里有Func函数的声明和实际调用
2. 编译
检查语法,生成汇编代码
生成Func.s和Test.s文件
Func.s里面是两个Func函数相关的汇编代码
Test.s里面有main函数调用相关的汇编代码
编译的时候,Test.s还没有call函数的地址
但是编译器可以让过
编译的时候,函数可能只有声明,如果有函数的声明可以和main函数里的调用对的上的话,暂时让过
函数的定义可能在其他文件里
3. 汇编
转换成CPU能认识的二进制机器码
生成Func.o和Test.o
4. 链接
合并到一起,链接一些没有确定的函数地址
生成a.out
如果没有函数定义
会报错,而且不是编译错误,而是LNK错误
函数名修饰规则
链接的时候,每个函数要找地址
如果只有声明,没有定义
没有地址,call的时候就只有一个问号
要找这个函数的地址
-
由于C语言没有同名函数,链接函数地址时,就用函数名去找。C语言里有个叫符号表的东西,只会记录函数名和地址的映射。所以不支持函数重载
-
而C++有函数重载,符号表里记录的是修饰下的函数名和地址的映射
Linux函数名修饰规则
_Z 函数名字符个数 函数名 参数首字母
Func(int a, char b)就是_Z4fic
Func(char b, int a)就是_Z4fci
找地址的时候,把参数带入进去修饰函数名,就根据修饰下的字符串去找
参数不同,修饰出来的名字就不同,就可以进行对应地找地址了