【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;传统…

LeetCode //C - 32. Longest Valid Parentheses

32. Longest Valid Parentheses Given a string containing just the characters ‘(’ and ‘)’, return the length of the longest valid (well-formed) parentheses substring. Example 1: Input: s “(()” Output: 2 Explanation: The longest valid parentheses s…

【刷题1】LeetCode 994. 腐烂的橘子 java题解

tag:图论 广度优先搜索 https://leetcode.cn/problems/rotting-oranges/description/?envTypestudy-plan-v2&envIdtop-100-liked 使用广度优先搜索&#xff0c;搜索步数就是分钟数&#xff0c;等到所有橘子都腐烂后&#xff0c;各个橘子腐烂的最长分钟数就是全部都烂的最小…

C语言-指针(上)

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

【文件管理】关于上传下载文件的设计

这里主要谈论的是产品设计里面的文件管理&#xff0c;比如文件的上传交互及背后影响到的前后端设计。 上传文件 场景&#xff1a;一条记录&#xff0c;比如个人信息&#xff0c;有姓名&#xff0c;出生年月&#xff0c;性别等一般的字段&#xff0c;还可以允许用户上传附件作为…

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;既可以做二分类、也可以做多分类&#…

python常用pandas函数nlargest 和 nsmallest及其手动实现

pandas是Python数据分析的重要工具之一&#xff0c;提供了大量便捷的数据操作方法。nlargest和nsmallest是pandas中两个非常实用的函数&#xff0c;它们可以帮助我们快速找出Series或DataFrame中最大或最小的n个值。 ### pandas中的nlargest和nsmallest函数 - nlargest(n, colu…

掌握Go语言:深入探究Go语言中的命令源码文件与参数处理技巧(3)

在Go语言学习的路上&#xff0c;掌握命令源码文件与参数处理技巧是至关重要的。本文将深入探讨命令源码文件的概念、作用以及参数处理的方法&#xff0c;同时结合进销存项目&#xff0c;展示实际应用与代码示例。 命令源码文件的概述 命令源码文件是Go语言程序的运行入口&…

uniapp的h5端在线预览文件

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

linux检测和重启python脚本

#!/bin/bash# 检测Flask应用是否挂了 if ! pgrep -f "flask_app.py" >/dev/null; then# 重启Flask应用cd /path/to/your/flask/appnohup python3 flask_app.py >/dev/null 2>&1 & fi这是一个简单的bash脚本&#xff0c;用于检测Flask应用是否挂掉&a…

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;会打断 …

ES7、ES8、ES9、ES10、ES11、ES12 新特性汇总合集

在过去几年里&#xff0c;ECMAScript 标准不断更新&#xff0c;引入了许多令人激动的功能和改进。让我们来看看从 ES7 到 ES12 各个版本带来的重要变化&#xff1a; 1. ES7&#xff08;ECMAScript 2016&#xff09; 1. Array.prototype.includes 方法 Array.prototype.includ…

【字符串左旋右旋不会做?快来看看这篇“弹幕滚动”,你就有思路了!】

前言 不知道大家在做题时有没有遇到过“字符串旋转”的题目&#xff0c;很多人可能没有思路&#xff0c;这里我不具体讲解单一的题目&#xff0c;而是展现一个“弹幕滚动”的示例&#xff0c;相信大家看懂后就能做出“字符串旋转”的题了&#xff01; 技术名词解释 1.什么是“…

关于决策树模型

决策树模型是一种常用的数据挖掘方法&#xff0c;它通过模拟人类决策过程来对数据进行分类或回归分析。决策树由节点和边组成&#xff0c;其中每个内部节点代表一个属性上的测试&#xff0c;每个分支代表测试的一个结果&#xff0c;而每个叶节点&#xff08;树的末端&#xff0…

Vue3 isProxy,isReactive,isReadonly 三者解析

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