【C++入门】缺省参数 | 函数重载

目录

4.缺省参数

4.1缺省参数的概念

4.2缺省参数分类

4.3声明和定义分离(声明使用缺省参数)

4.🐍声明和定义分离到链接

5.函数重载

5.1函数重载的概念

5.2可执行程序的形成步骤

5.3C++支持函数重载的原理—名字修饰(name Mangling)


4.缺省参数

4.1缺省参数的概念

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

#include<iostream>
using namespace std;void Func(int a = 0)
{cout << a << endl;
}
int main()
{Func(); // 没有传参时,使用参数的默认值Func(10); // 传参时,使用指定的实参return 0;
}

4.2缺省参数分类

  • 全缺省参数
  • 半缺省参数
  • 函数在给半缺省参数,必须是从右往左连续依次给出,不能间隔跳跃。(从第一个开始)
  • 调用函数传参:必须从左到右连续传参,不能跳跃。(从第一个开始)
  • 形式参数是实际参数的一份临时拷贝。
  • 缺省参数不能在函数声明和定义中同时出现,若有声明只能在声明中出现。
  • 缺省值必须是常量或者全局变量。
  • C语言不支持(编译器不支持。
//全缺省参数
void Func(int a = 10, int b = 20, int c = 30)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl;
}
//半缺省参数
void Func(int a, int b = 10, int c = 20)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl;
}
//给半缺省参数
#include<iostream>
using namespace std;
//半缺省参数
void Func2(int a, int b = 10, int c = 20)
void Func2(int a, int b , int c = 20)
void Func2(int a, int b, int c)
//❌void Func2(int a, int b = 10, int c)
//❌void Func2(int a=10, int b, int c = 20)
{cout << "a = " << a ;cout << "b = " << b ;cout << "c = " << c ;cout << endl;
}
//调用传参
#include<iostream>
using namespace std;
//全缺省参数
void Func1(int a = 10, int b = 20, int c = 30)
{cout << "a = " << a ;cout << "b = " << b ;cout << "c = " << c ;cout << endl;
}
int main()
{Func1(1, 2, 3);Func1(1, 2);Func1(1);Func1();//Func1(, 2, );//❌return 0;
}

 

4.3声明和定义分离(声明使用缺省参数)

如果声明与定义位置同时出现缺省参数,恰巧两个位置提供的值不同,那编译器就无法确定到底该用那个缺省值❓

在声明处给缺省参数。因为.cpp在预处理阶段会展开头文件.h。会把.h的声明拷贝到.cpp里面。在后面编译阶段,检查语法也不会出错。

 //a.hvoid Func(int a = 10);//a.cppvoid Func(int a = 20)
{///
}
// 注意:如果声明与定义位置同时有缺省参数,
//恰巧两个位置提供的值不同,那编译器就无法确定到底该用那个缺省值。

4.🐍声明和定义分离到链接

tips:

从语法的角度:函数名就是函数的地址。

从底层的角度:函数调用的本质是call  函数(地址)(物理空间是连续的)

地址是函数的地址。函数底层也是一堆指令。也就是函数底层指令的第一条指令的地址。

CPU执行也是执行指令。 

声明和定义分离,编译阶段检查语法call Func(❓)里面是没有地址的,还没有链接。那编译阶段检查语法为什么不会报错。(前面预处理/编译/汇编阶段是各自走各自的)

  • 编译阶段:语法检查(自定义类型/变量/函数 搜索出处)
  • 汇编阶段,编译器就只是搜索找到声明(承诺)
  • 链接阶段,形成了符号表。
  • 编译器去符号表里搜索,找到函数定义(兑现承诺)
  • 编译器把函数定义的地址放到 call Func(07FF7F71E12E4h)
  • 符号表

//"a.cpp"
#include"a.h"
void Func(int a)
{cout << a << endl;
}//"a.h"
#pragma once
#include<iostream>
using namespace std;
void Func(int a =20);//test.cpp
#include"a.h"
int main()
{Func();Func(10);return 0;
}

在编译阶段没有找到声明:语法错误❌

在链接阶段没有找到定义:链接❌

5.函数重载

自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了。函数重载也就是一词多义
比如:以前有一个笑话,国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个是男足。前者是“谁也赢不了!”,后者是“谁也赢不了!” 

5.1函数重载的概念

函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。

  • C语言不允许同名函数
  • C++语言允许同名函数。
  • 要求:函数名相同,参数不同,构成函数重载。(编译器会根据数据类型自动匹配)
  • 参数不同:
  1. 参数类型不同
  2. 参数个数不同
  3. 参数类型顺序不同
#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.2可执行程序的形成步骤

在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接。

(前面缺省参数的声明和定义分离铺垫过了)

 

  • 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.面对链接函数的地址到括号里:call  函数(函数地址)
  • C语言符号表:函数名 函数地址
  • C++符号表的规则:函数名且包含函数参数类型等  函数地址(那么链接时,面对Add函数,链接器会使用哪个方式去符号表找呢?这里每个编译器都有自己的函数名修饰规则。只要能区分开即可)(下面细讲)

5.3C++支持函数重载的原理—名字修饰(name Mangling)

C语言不支持函数重载?C++如何支持函数重载?

>>>>>>>>>   和前面我们讲到的声明和定义分离到链接中链接步骤(符号表搜索函数地址)

>>>>>>>>>(在符号表中去搜索函数地址)这个步骤非常关键。

C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分。


 【C语言】 

C语言在符号表中去搜索函数地址 >>>>只根据函数名搜索函数地址,当然C语言不支持函数重载。C语言链接时,直接用函数名去找地址,有同名函数,区分不开。


 【C++】

祖师爷为了C++能够支持函数重载,于是把搜索规则改变了。C++在符号表去搜索函数地址,规则>>>>>>>>>>>>>>>>>>>函数名且包含函数参数类型等  函数地址,支持函数重载。

这里每个编译器都有自己的函数名修饰规则。函数名修饰规则,名字中引入参数类型,各个编译器有自己的实现一套。(下面从windows和Linux举例)

【windows下名字修饰规则】 

【扩展学习:C/C++函数调用约定和名字修饰规则--有兴趣好奇的可以看看,里面
有对vs下函数名修饰规则讲解】C/C++ 函数调用约定___declspec(dllexport) void test2();-CSDN博客

#include<iostream>
using namespace std;
int Add(int left, int right);
double Add(double left, double right);
int main()
{Add(10, 20);Add(10.1, 20.2);
}
//可以去VS上只有声明没有定义,此时就会报链接错误❌

【Linux下名字修饰规则】

通过下面我们可以看出gcc的函数修饰后名字不变。而g++的函数修饰后变成【_Z+函数长度+函数名+类型首字母】。

  • 采用C语言编译器编译后结果
  • 结论:在linux下,采用gcc编译完成后,函数名字的修饰没有发生改变。
  • 采用C++编译器编译后结果
  • 结论:在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参
    数类型信息添加到修改后的名字中。
      #include<stdio.h>                            2 int Add(int a,int b)                 3 {                                    4     return a+b;                      5 }                                    6 void func(int a,double b,int* p)     7 {                                    8                                      9 }                                    10 int main()                           11 {                                    12     Add(1,2);                        13     func(1,2,0);                     14     return 0;                        15 }   
  • 采用C语言编译器编译后结果
gcc -o projectC project.c
objdump -S projectC

  • 采用C++编译器编译后结果
g++ -o proejctCPP project.cpp
objdump -S projectCPP(proejctCPP)

对比Linux会发现,windows下vs编译器对函数名字修饰规则相对复杂难懂,但道理都
是类似的,我们就不做细致的研究了。 🙂感谢大家的阅读,若有错误和不足,欢迎指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/715039.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux学习之信号

目录 1.信号的概念 2.信号的产生 3.信号的保存 4.信号的捕捉 信号的其它内容&#xff1a; SIGCHLD信号 1.信号的概念 在Linux中&#xff0c;信号是一种用于进程之间通信的基本机制。它是一种异步事件通知&#xff0c;用于通知进程发生了某些事件。如下是一些常见的Linux信…

[计算机网络]--五种IO模型和select

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、五种IO…

线性规划问题的高斯消元法

线性规划的算法和解方程组的方法很像,常用的方程组的解法叫做高斯消元法,对于高斯消元法的基本流程,现给定一组线性方程: 添加图片注释,不超过 140 字(可选) 对于给定的线性方程组,目的是将方程组中同时能够满足三个等式的变量x,y,z求解出来,对于高斯消元法的基本过程…

【精通Spring】基于注解管理Bean

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

集智书童 | YOLO+混合注意力机制 | YOLOv5再加4.3%才可以做对手,Transformer混合设计依旧可以卷

本文来源公众号“集智书童”&#xff0c;侵权删&#xff0c;干货满满。YOLOv5重出江湖&#xff01; 原文链接&#xff1a;https://mp.weixin.qq.com/s/vb7HsA0fKDgRc3uC8Z-2yw 在工业生产过程中&#xff0c;由于低效率、不统一的评估、高成本以及缺乏实时数据&#xff0c;传统…

C语言-指针(上)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 本篇文章将为大家介绍C语言中的核心内容-指针&#xff0c;指针在C语言的中知识内容比…

Java 小项目开发日记 04(文章接口的开发、oss图片上传)

Java 小项目开发日记 04&#xff08;文章接口的开发、oss图片上传&#xff09; 项目目录 配置文件&#xff08;pom.xml&#xff09; <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:sc…

机器学习:集成学习(Python)

一、Adaboost算法 1.1 Adaboost分类算法 adaboost_discrete_c.py import numpy as np import copy from ch4.decision_tree_C import DecisionTreeClassifierclass AdaBoostClassifier:"""adaboost分类算法&#xff1a;既可以做二分类、也可以做多分类&#…

uniapp的h5端在线预览文件

步骤如下&#xff1a; 1、下载需要准备的工具文件包 2、将其解压到/static/pdf文件夹下,如图&#xff1a; 3、创建在线查看文件的页面&#xff1a; <template><view><web-view :src"path"></web-view></view> </template>&l…

JavaScript练手小技巧:一文看懂<script>标签的 ansyc 和 defer

<script>标签的 ansyc 和 defer 属性。只对外部加载 JS 文件有效。 <script src"js/app.js" async></script> <script src"js/app.js" defer></script> 普通加载 js&#xff08;同步加载&#xff09;&#xff1a;会打断 …

Vue3 isProxy,isReactive,isReadonly 三者解析

1、isProxy 作用&#xff1a;判断当前数据是否为代理数据。 注意&#xff1a;它只对通过 reactive&#xff0c;readonly&#xff0c;shallowReactive&#xff0c;shallowReadonly 这四个方法包裹的数据返回true&#xff0c;对于 ref 以及通过 new Proxy 代理的数据返回都是fal…

ChatGPT科研与AI绘图及论文高效写作教程

原文链接&#xff1a;ChatGPT科研与AI绘图及论文高效写作教程 2023年随着OpenAI开发者大会的召开&#xff0c;最重磅更新当属GPTs&#xff0c;多模态API&#xff0c;未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚于互联网和个人电…

HPE ProLiant MicroServer Gen8更换坏硬盘(RAID 1+0)

HPE ProLiant MicroServer Gen8今天硬盘告警&#xff0c;坏了一块硬盘&#xff08;估计还是由于上次突然断电导致的&#xff09;&#xff0c;关机&#xff0c;拆下坏硬盘&#xff0c;更换新硬盘&#xff0c;开机后按了一次F1键&#xff0c;系统继续启动并正常使用&#xff0c;同…

高性能MySQL 第4版

第一章MySQL架构 MySQL提供了多种锁的颗粒度&#xff0c;每种MySQL存储引擎都可以实现自己的锁策略和锁力度。 行级锁是在存储引擎而不是在服务器中实现的。 隔离界别 READ UNCOMMITTED - 脏读 在事务中可以可以查看到其他事务中还没有提交的修改。实际中很少用。 READ C…

Linux网络编程——socket 通信基础

Linux网络编程——socket 通信基础 1. socket 介绍2. 字节序2.1 简介2.2 字节序举例2.3 字节序转换函数 3. socket 地址3.1 通用 socket 地址3.2 专用 socket 地址 4. IP地址转换&#xff08;字符串ip -> 整数&#xff0c;主机、网络字节序的转换 &#xff09;5. TCP 通信流…

算法------(13)KMP

例题&#xff1a;&#xff08;1&#xff09;AcWing 831. KMP字符串 。。其实写完也不太理解。。随便写点吧 KMP就是求next数组和运用next的数组的过程。相比传统匹配模式一次更新一单位距离的慢速方法&#xff0c;next数组可以让下表字符串一次更新n - next【n】个距离&#x…

Java读取文件

读取文件为String 、访问链接直接跳转html 环境&#xff1a;SpringMVC 、前端jsp InputStreamReader FileInputStream fileInputStream new FileInputStream(formatFile.getHtmlpath());InputStreamReader reader new InputStreamReader(fileInputStream, StandardCharsets…

【EAI 026】RoboGen: 通过自动数据生成管线实现机器人技能学习

Paper Card 论文标题&#xff1a;RoboGen: Towards Unleashing Infinite Data for Automated Robot Learning via Generative Simulation 论文作者&#xff1a;Yufei Wang, Zhou Xian, Feng Chen, Tsun-Hsuan Wang, Yian Wang, Zackory Erickson, David Held, Chuang Gan 作者单…

C++:菱形继承问题

目录 1、什么是菱形继承 2、虚拟继承 3、一些常见问题 1. 什么是菱形继承&#xff1f;菱形继承的问题是什么&#xff1f; 2. 什么是菱形虚拟继承&#xff1f;如何解决数据冗余和二义性的 3. 继承和组合的区别&#xff1f;什么时候用继承&#xff1f;什么时候用组合&#…

Qt 自定义长条进度条(类似播放器进度条)

1.运行界面 2.步骤 其实很简单。 2.1绘制底图圆角矩形 2.2绘制播放进度圆角矩形 参考&#xff1a;painter绘图 3.源码 #pragma once#include <QWidget> #include <QLabel> #include <QHBoxLayout> #include <QMouseEvent> #include <QDebug&g…