2. C++入门:缺省参数及函数重载

缺省参数

缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。

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;
}

三个缺省参数,变化出四种调用方式
![[Pasted image 20240513210346.png]]

注意

  • 不可以跳跃着传
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;
}

注意

  • 缺省值只能从右往左给,必须是连续给,这样传参也是连续的。
  • 从左往右缺省,传参的时候会有歧义,从右往左缺省不会产生歧义
  • 不能间隔着给缺省值
不能声明和定义同时存在
  1. 函数的声明和定义同时有缺省参数,会报错
    因为怕声明和定义分别给不同的缺省参数,这样不知道以谁为准
  2. 也不能只在定义中给,声明中不给
    用这个函数的时候,有可能只包含了声明头文件
    这样在另外一个文件用的时候,include ”xxx.h“
    如果声明文件里没有缺省参数,就不知道这个函数没传参的时候给多少
  3. 所以最好的方式就是在函数声明的时候给缺省参数
#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++支持
![[Pasted image 20240513213948.png]]

会调用不同的函数

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;
}
前置知识

程序编译过程:
![[Pasted image 20240514121333.png]]

编译器对多文件进行编译的时候
会进行

1. 预处理

头文件展开/宏替换/条件编译/去掉注释…

其中头文件展开,会将Fun.h拷贝过去
不过只是直接拷贝到文件里
编译器会生成Func.i和Test.i文件

Func.i文件里有Func函数的声明和定义
Test.i文件里有Func函数的声明和实际调用

2. 编译

检查语法,生成汇编代码
生成Func.s和Test.s文件
Func.s里面是两个Func函数相关的汇编代码
![[Pasted image 20240513224455.png]]

Test.s里面有main函数调用相关的汇编代码
![[Pasted image 20240513224113.png]]

编译的时候,Test.s还没有call函数的地址
但是编译器可以让过
编译的时候,函数可能只有声明,如果有函数的声明可以和main函数里的调用对的上的话,暂时让过
函数的定义可能在其他文件里

3. 汇编

转换成CPU能认识的二进制机器码
生成Func.o和Test.o

4. 链接

合并到一起,链接一些没有确定的函数地址
生成a.out
如果没有函数定义
![[Pasted image 20240513231036.png]]

会报错,而且不是编译错误,而是LNK错误

函数名修饰规则

链接的时候,每个函数要找地址
如果只有声明,没有定义
没有地址,call的时候就只有一个问号
要找这个函数的地址

  1. 由于C语言没有同名函数,链接函数地址时,就用函数名去找。C语言里有个叫符号表的东西,只会记录函数名和地址的映射。所以不支持函数重载
    ![[Pasted image 20240514121926.png]]

  2. 而C++有函数重载,符号表里记录的是修饰下的函数名和地址的映射
    Linux函数名修饰规则
    _Z 函数名字符个数 函数名 参数首字母
    Func(int a, char b)就是_Z4fic
    Func(char b, int a)就是_Z4fci
    ![[Pasted image 20240514121944.png]]

找地址的时候,把参数带入进去修饰函数名,就根据修饰下的字符串去找
参数不同,修饰出来的名字就不同,就可以进行对应地找地址了

  • 28
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是DS小龙哥编写整理的C++入门指南PDF文档,适合C++初学者,C语言转C++工程师当做入门工具书学习。PDF里有完整示例、知识讲解,平时开发都可以复制粘贴,非常便捷。 目前一共写了7章,后续会持续更新资源包,更新后重新下载即可。 这是目前书籍的目录: C++入门指南 1 一、 C++语言基本介绍与开发环境搭建 1 1.1 C++简介 1 1.2 面向对象编程 1 1.3 Windows系统下搭建C++学习环境 2 二、C++基础入门 16 2.1 C++类和对象 17 2.2 C++命名空间 18 2.3 std标准命名空间 20 2.4 C++新增的标准输入输出方法(cin和cout) 22 2.5 C++规定的变量定义位置 24 2.6 C++新增的布尔类型(bool) 24 2.7 C++ 新增的new和delete运算符 25 2.8 C++函数的默认参数(参数) 26 2.9 C++函数重载详解 28 2.10 C++新增的引用语法 30 三、 C++面向对象:类和对象 34 3.1 类的定义和对象的创建 34 3.2 类的成员变量和成员函数 36 3.3 类成员的访问权限以及类的封装 38 3.4 C++类的构造函数与析构函数 39 3.5 对象数组 47 3.6 this指针 50 3.7 static静态成员变量 52 3.8 static静态成员函数 53 3.9 const成员变量和成员函数 55 3.10 const对象(常对象) 56 3.11 友元函数和友元类 58 3.11.3 友元类 61 3.12 C++字符串 62 四、C++面向对象:继承与派生 75 4.1 继承与派生概念介绍 75 4.2 继承的语法介绍 75 4.3 继承方式介绍(继承的权限) 76 4.4 继承时变量与函数名字遮蔽问题 79 4.5 基类和派生类的构造函数 82 4.6 基类和派生类的析构函数 83 4.7 多继承 85 4.8 虚继承和虚基类 88 五、C++多态与抽象类 91 5.1 多态概念介绍 91 5.2 虚函数 92 5.3 纯虚函数和抽象类 95 六、C++运算符重载 97 6.1 运算符重载语法介绍 97 6.2 可重载运算符与不可重载运算符 98 6.3 一元运算符重载 99 6.4 二元运算符重载 102 6.5 关系运算符重载 104 6.6 输入/输出运算符重载(>>、<<) 105 6.7 函数调用运算符 () 重载 106 6.8 重载[ ](下标运算符) 107 七、C++模板和泛型程序设计 108 7.1 函数模板 108 7.2 类模板 110

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值