【C++】巧用缺省参数与函数重载:提升编程效率的秘密武器

简介: 【C++】巧用缺省参数与函数重载:提升编程效率的秘密武器

一、缺省参数

1.1 缺省参数的概念

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

#include <iostream>
using namespace str;
void Func(int a=0)
{
    count<<a<<endl
}
int main()
{
    Func();//0
    Func(10);//10
}
1.没有传参,使用参数的默认值
2.传参,使用指定的参数

1.2 缺省函数分类

全缺省函数:

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

1.3 正确使用缺省参数前提

第一点重点):

  1. 缺省参数不能在函数声明和定义同时出现

说明:从两个方面来说,一方面如果声明与定义位置同时出现,恰好两个位置提供的值不同,那么编译器就无法确定到底该使用哪个缺省值,另一个方面来说就算两个位置提供的值相同,祖师爷规定也不能这种方式操作

2.缺省参数选择在函数声明出现

说明:一般将声明放在头文件中,而头文件将在编译阶段进行展开进行语法检查。对于函数地址而言是用于执行一堆指令(Call 函数中指令)到CPU中处理,那么函数地址是第一个指令地址,而函数定义才会使用到地址,函数声明不存在有效地址。

那么在编译阶段,对于函数声明编译器选择放过呢?由于编译器是进行语法分析,在链接时,函数声明会通过无效地址到符号表定位到真正函数的地址。

重定位就是在链接地址跟运行地址不同的情况下,执行一段位置无关码,这段位置无关码的作用就是将原来的那份代码全部复制到链接地址那里去,然后自己再长跳转到新的那份代码的刚刚执行的那个位置。这样就实现了链接地址跟运行地址一致的情况

具体场景辅助理解:

你要买房需要首付30w,现在手头只有20w,打了一通你的室友电话,你的室友同意借你10w。到首付的时候,你室友的10w迟迟没有到账,后面才知道你室友家破产了,借不出去答应借你10w(声明/承诺)

  • 答应借你10w(声明/承诺)
  • 转账给你10w(定义/兑现)

第二点:

  • 半缺省实(或形)参数必须从右往左依次来给出,不允许间隔着给

说明:在语法层次上,我们属于学习者是根据语法规定来进行学习。如果想要更有说服力的答案,在调试阶段,通过鼠标右边点击反汇编,从图中我们可以得到传参是传参是从右到左push数据

部分补充:

  • 缺省参数必须是常量或者全局变量
  • C语言不支持缺省参数

缺省参数使用场景:无法得知插入准确值

//1.确定要插入100个数据
StackInit(&st1, 100);
//1.确定要插入10个数据
StackInit(&st2, 10);
// 3、不知道要插入多少个
StackInit(&st3);

二、函数重载

自然语言中,一个词可以有多重含义,人们可以通过上下文来判断词真实的含义,该词被重载了。(有卧龙必有凤雏)

2.1 函数重载概念

函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,常用来处理实现功能类似数据类型不同的问题,而C语言不允许同名函数

2.2 使用函数重载前提

函数重载需要满足其中一个条件:

  1. 参数类型不同
  2. 参数个数不同
  3. 参数类型顺序不同(本质是参数类型不同)
#include<iostream>
using namespace std;
// 1、参数类型不同
int Add(int x,int y)
{
    return x+y;
}
int Add(double x,double y)
{
    return x+y;
}
// 2、参数个数不同
void f()
{
    cout<<"f()"<<endl;
}
void f(int a)
{
    cout<<"f(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); //call(?)
  Add(10.1, 20.2); //call(?)
    
    f();
  f(10);
    
    f(10, 'a');
  f('a', 10);
    return 0;
}

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

我们知道C语言不支持函数重载,那么C++如何去支持函数重载呢?

f(10, 'a');  //call(?)
  f('a', 10);  //call(?)

首先简单快速过一遍,关于程序在编译环境下的流程

在C/C++,程序运行之前,需要进行以下几个阶段:预处理、编译、汇编、链接

每个编译器都有属于自己的一套函数名修饰规则windows下vs的修饰规则过于复杂,而Linux下g++的修饰规则简单

int Add(int a,int b)
{
    return a+b;
}
void func(int a,double b,int *p)
{}
int main()
{
    Add(1,2);
    func(1,2,0);
        return0
}

采用C语言编译器

采用C++编译器

  • C语言在linux下,采用gcc编译完成后,函数名字的修饰没有发生改变
  • C++在linux下,采用gcc编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修饰后名字中

梳理:由于C语言在链接时,直接使用函数名去找地址,同名函数无法区分不开。C++可以通过函数名修饰规则,将名字引入参数类型(不同编译器有不同规则)。只要参数不同,修饰出来的名字就不一样,就支持了重载。(如果两个函数的函数名和参数时一样的,返回值不同是不构成重载的)


以上就是本篇文章的所有内容,在此感谢大家的观看!这里是店小二呀C++笔记,希望对你在学习C++语言旅途中有所帮助!


相关文章
|
3月前
|
存储 C++ UED
【实战指南】4步实现C++插件化编程,轻松实现功能定制与扩展
本文介绍了如何通过四步实现C++插件化编程,实现功能定制与扩展。主要内容包括引言、概述、需求分析、设计方案、详细设计、验证和总结。通过动态加载功能模块,实现软件的高度灵活性和可扩展性,支持快速定制和市场变化响应。具体步骤涉及配置文件构建、模块编译、动态库入口实现和主程序加载。验证部分展示了模块加载成功的日志和配置信息。总结中强调了插件化编程的优势及其在多个方面的应用。
426 69
|
3月前
|
安全 程序员 编译器
【实战经验】17个C++编程常见错误及其解决方案
想必不少程序员都有类似的经历:辛苦敲完项目代码,内心满是对作品品质的自信,然而当静态扫描工具登场时,却揭示出诸多隐藏的警告问题。为了让自己的编程之路更加顺畅,也为了持续精进技艺,我想借此机会汇总分享那些常被我们无意间忽视却又导致警告的编程小细节,以此作为对未来的自我警示和提升。
372 14
|
2月前
|
消息中间件 存储 安全
|
3月前
|
存储 搜索推荐 C++
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
69 2
|
3月前
|
程序员 C++
C++中的函数重载有什么作用
【10月更文挑战第19天】C++中的函数重载有什么作用
30 3
|
3月前
|
安全 程序员 编译器
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
96 11
|
3月前
|
存储 编译器 C++
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
55 9
|
3月前
|
存储 C++ 容器
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器1
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
76 5
|
3月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
72 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
3月前
|
算法 编译器 C++
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
99 2