目录
缺省参数
缺省参数的分类
全缺省参数
半缺省参数
缺省参数应用
占位参数
函数重载
函数重载注意事项
C++支持函数重载的原理
缺省参数
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。
在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
#include <iostream>
using namespace std;
void F(int a = 0)
{
cout << "a = " << a << endl;
}
int main()
{
F();//未指定实参,使用参数的默认值
F(10);//传参时,使用指定的实参
return 0;
}
缺省参数的分类
全缺省参数
void F(int a = 10, int b = 20, int c = 30)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
cout << endl;
}
int main()
{
F(100);
F(100, 200);
F(100, 200,300);
//传参时,必须从左往右依次给
//错误示例:
//F(100, ,300);
return 0;
}
半缺省参数
void F(int a , int b , int c = 30)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
cout << endl;
}
int main()
{
F(100,200);
F(100, 200, 300);
return 0;
}
注意:
1. 半缺省参数必须从右往左依次来给出,不能间隔着给;
//错误示例
void F(int a=10, int b, int c = 30)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
cout << endl;
}
2. 缺省参数不能在函数声明和定义中同时出现;
//错误示例
//test.cpp中定义
F(int a = 10);
//test.h中声明
F(int a = 20);
//编译器会报错
3. 缺省值必须是常量或者全局变量;
4. C语言不支持(编译器不支持);
缺省参数应用
在之前数据结构的学习中,我们经常用到某个函数给来实现对某种数据结构的初始化(以栈为例);
struct Stack
{
int* a;
int top;
int capacity;
};
void StackInit(struct Stack* ps)
{
int capacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
ps->a = (int*)malloc(sizeof(int) * capacity);
if (ps->a == NULL)
{
perror("malloc fail");
return;
}
//...
}
这样的写法有一个缺点,不管我们需要多大的空间,每次调用初始化函数时第一次都只能开辟4的空间,看着很呆板。
但是运用缺省参数改进后:
void StackInit(struct Stack* ps, int defaultcapacity=4)
{
ps->a = (int*)malloc(sizeof(int) * defaultcapacity);
if (ps->a == NULL)
{
perror("malloc fail");
return;
}
//...
}
当我们想指定开辟多大空间时只需要多传一个参数就可以了,否则默认为4。
当然除了这样的使用场景,缺省参数可以运用于很多很多场景,使得代码灵活性更高!
占位参数
C++中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置
语法: 返回值类型 函数名 (数据类型){}
//函数占位参数 ,占位参数也可以有默认参数
void func(int a, int) {
cout << "this is func" << endl;
}
int main() {
func(10,10); //占位参数必须填补
system("pause");
return 0;
}
函数重载
作用:函数名可以相同,提高复用性
函数重载满足条件:
-
同一个作用域下
-
函数名称相同
-
函数参数类型不同 或者 个数不同 或者 顺序不同
注意: 函数的返回值不可以作为函数重载的条件
示例:
//函数重载需要函数都在同一个作用域下
void func()
{
cout << "func 的调用!" << endl;
}
void func(int a)
{
cout << "func (int a) 的调用!" << endl;
}
void func(double a)
{
cout << "func (double a)的调用!" << endl;
}
void func(int a ,double b)
{
cout << "func (int a ,double b) 的调用!" << endl;
}
void func(double a ,int b)
{
cout << "func (double a ,int b)的调用!" << endl;
}
//函数返回值不可以作为函数重载条件
//int func(double a, int b)
//{
// cout << "func (double a ,int b)的调用!" << endl;
//}
int main() {
func();
func(10);
func(3.14);
func(10,3.14);
func(3.14 , 10);
system("pause");
return 0;
}
函数重载注意事项
-
引用作为重载条件
-
函数重载碰到函数默认参数
//函数重载注意事项
//1、引用作为重载条件
void func(int &a)
{
cout << "func (int &a) 调用 " << endl;
}
void func(const int &a)
{
cout << "func (const int &a) 调用 " << endl;
}
//2、函数重载碰到函数默认参数
void func2(int a, int b = 10)
{
cout << "func2(int a, int b = 10) 调用" << endl;
}
void func2(int a)
{
cout << "func2(int a) 调用" << endl;
}
int main() {
int a = 10;
func(a); //调用无const
func(10);//调用有const
//func2(10); //碰到默认参数产生歧义,需要避免
system("pause");
return 0;
}
C++支持函数重载的原理
我们用函数重载定义函数Add,在我们眼中,两个函数名字相同,参数不同,调用函数时,我们知道应该调用哪个,那么编译器在链接阶段,如何知道去哪寻找对应的函数栈帧呢?
int Add(int a, int b)
{
return a + b;
}
double Add(double a, double b)
{
return a + b;
}
int main()
{
Add(10, 20);
Add(2.2, 3.3);
return 0;
}
其实编译器在编译与汇编阶段,会对函数名做修饰。不同的编译器对函数名的修饰也不同,为了方便观察,这里以Linux环境下的g++编译器为例。输入指令查看可执行程序反汇编的代码:
g++ Test.cpp -o Testcpp
objdump -S Testcpp
以下是Linux下g++修饰的汇编代码:
为了作对比,我们再看看没有函数重载的C语言是否会对函数名做修饰:
gcc Test.c -o Testc
objdump -S Testc
C代码:
#include<stdio.h>
int Add_int(int a, int b)
{
return a + b;
}
double Add_double(double a, double b)
{
return a + b;
}
int main()
{
Add_int(10, 20);
Add_double(2.2, 3.3);
return 0;
}
汇编代码:
通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。
最后补充,如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分。