当前位置: 首页 > article >正文

C++基础02(函数)

文章目录

    • 函数function
      • 内置函数
      • 函数重载
        • 可以形成重载的情形
        • **不可以形成重载的情形**
      • 函数模板
      • 关键字auto
      • 函数默认参数

函数function

1.函数的概念:为了实现特定功能所组织起来代码的集合

2.函数的作用:1.代码复用2.分解过程

3.函数的定义格式:

​ 返回类型 函数名([形参列表])

​ {

​ 函数体

​ }

4.函数调用格式:函数名([实参列表]);

5.函数的分类:

​ 根据有无形参:有参函数,无参函数

​ 根据返回值:有返回值函数和无返回值函数

​ 从作用域角度:内部函数static 外部函数

​ 从用户的角度:系统函数,自定义函数

6.函数的返回值

​ 函数返回结果,可以通过return这个关键字实现值的返回,一次只能返回一个。

​ return:返回一个值

​ 终止当前函数

​ 如果希望函数向外界返回多个结果:通过指针类型的形参进行返回,return配合输出型形参,全局变量,把多个值封装在一个结构体进行返回

内置函数

目的:提高程序的执行效率(省略了函数调用时的现场包含和回复现场的动作语句)

调用函数时需要一定的时间和空间的开销。如图为函数调用的过程:

在这里插入图片描述
C++提供一种提高效率的方法,即在编译时将所调用函数的代码直接嵌入到主调函数中,而不是将流程转出去。这种嵌入到主调函数中的函数称为内置函数(inline function),又称内嵌函数。有称为内联函数。

指定内置函数的方式 为:在函数首行的左端加一个关键字inline即可。

#include<iostream>
#include<iomanip>
using namespace std; 
 int add(int a, int b);//对于内联函数,在声明时可以加inline关键字 也可以省略。

//内置函数的使用场景:某个函数在程序中被频繁调用,且该函数的语句没有超过5句的情况下,此时该函数就适合定义为内置函数

//inline关键字要放在函数返回类型的前面   -----目的 提高程序的执行效率 (省略了函数调用时的现场包含和恢复现场的动作语句)
inline int add(int a, int b) //被inline关键字修饰的函数 我们称为内置函数,内联函数或内嵌函数
{


    return a + b;
}

int main()
{
  //一个函数一旦被标定为内联函数,此时在堆该函数的调用语句编译时,会将该函数的函数体语句替换该调用语句
   int ret= add(10, 20);//内联函数的调用可以像普通函数一样去调用   10+20
   cout << ret << endl;

    return 0;
}

注意:

可以在声明函数和定义函数时同时写inline,也可以只在其中一处声明inline,效果相同,都能按内置函数处理。

使用内置函数可以节省运行时间,但却增加了目标程序的长度,因此一般只将规模很小(一般为5个语句一下)而使用频繁的函数(如定时采集数据的函数)声明为内置函数。

内置函数中不能包括复杂的控制语句,如循环语句和switch语句。

应当说明:对函数作inline声明,只是程序设计者对编译系统提出的一个建议,也就是说它是建议性的,而不是指令性的。并非一经指定为inline,编译系统就必须这样做。编译系统会根据具体情况决定是否这样做。

归纳起来,只有那些规模较小而又被频繁调用的简单函数,才适合声明为inline函数。

函数重载

在C语言中,相同作用域内的重名函数会引起冲突,哪怕它们拥有不同的参数列表也不行,而在C++中,重名函数只要满足一定的要求,可以同时存在,这大大拓展了函数设计的灵活性。这种重名且可并存的语法机制,被称为函数重载

C++中大量存在重载的函数,这些同名函数实际上就是一个函数的不同版本。比如,C++中的标准字符串类型 string 中的构造函数拥有 6 个不同的版本

string ( const string& str );
string ( const string& str, size_t pos, size_t n = npos ); 
string ( const char * s, size_t n ); 
string ( const char * s ); 
string ( size_t n, char c );

这些名称相同的函数,都存在于同一名字空间中,怎样才能形成合理合法的重载而不会冲突呢?这个问题的答案比较复杂,总体的基本原则是,只要让系统在使用它们的时候,可以有效地区分各个不同的版本,那它们就可以形成合法的重载版本

示例1:

#include<iostream>
#include<iomanip>
using namespace std; 


//下边这两个函数能重载成功,原因在于类型不一样
void add(const int* a)
{
    cout << "two int1" << endl;
}

void  add(int* a)
{
    cout << "two int" << endl;
  
}




int main()
{
    const int a = 10;
    add(&a);
    return 0;
}

在这里插入图片描述

可以形成重载的情形
  • 参数个数不同
  • 参数类型不同
  • 类方法(即类内部的函数)的 const 属性可以构成重载
  • 普通指针与常目标指针可以构成重载

示例2:

#include<iostream>
#include<iomanip>
using namespace std; 


//函数重载:就时在同一个作用域下,定义多个同名函数,但是要确保这些函数之间的参数个数或类型不相同
int add(int a, int b)
{
    cout << "two int" << endl;
    return a + b;
}

int add(int a, int b,int c) //这个函数确保的是函数之间参数个数不一样
{
    cout << "three int" << endl;
    return a + b+c;
}

float add(float a, float b) //与第一个相比,是类型不一样
{
    cout << "float" << endl;
    return a + b;
}

string add(string a, string b) //函数重载能否成功 和函数的返回类型是没有关系
{
    cout << "string" << endl;

    return a + b;
}




int main()
{
    add(10, 20);//对于重载函数的调用,它会根据调用语句所提供的实参类型或个数来匹配对应的函数
    add("baozhang", "tongzuo");

    return 0;
}

在这里插入图片描述

不可以形成重载的情形
  • 函数名、函数参数列表完全一致。
  • 函数的返回值类型差异。
  • 静态函数声明(static)。
  • const型变量(包括常指针)。

示例代码:

// 函数名、参数列表完全一致,仅靠返回值类型
// 的差异,将无法形成重载,这两个函数将会冲突
void  f1(int a);
float f1(int a);

// static不能形成重载,以下两个函数将会冲突
       int f2(int a);
static int f2(int a);


// const型变量(包括常指针),不能形成重载
void f3(      int a);
void f3(const int a);

void f4(char *p);
void f4(char *const p);

函数模板

所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能

示例:

#include <iostream>
using namespace std;

// 函数模板的定义
template <typename T> // 这里的T代表一个虚拟的类型
T add(T a, T b)       // 声明的虚拟类型可以在函数的返回类型,形参类型和函数体中来使用
{
    return a + b;
}

int main(int argc, char const *argv[])
{

    cout << add(10,20) << endl;
    cout << add(10.2,20.3) << endl;
    cout << add('a','b') << endl;

    return 0;
}

在这里插入图片描述
可以看到,用函数模板比函数重载更方便,程序更

简洁。但应注意它只适用于函数的参数个数相同而

类型不同,且函数体相同的情况,如果参数的个数

不同,则不能用函数模板。

关键字auto

在C语言中,auto 用来声明一个存储在的变量,因此它只能用来修饰临时变量,不能用来修饰全局变量、静态变量,与此同时临时变量本身默认就是存储在栈中,因此在C语言中,auto 基本上是作废的。

在C++中,auto 代表自动获得数据的类型,比如:

auto a = 100; // 等价于: int a = 100;

然,上述代码仅是语法示例,无法体现 auto 的价值,在C++的函数模板、类模板中,利用 auto 自动获得数据类型,往往有奇效,例如:

// 以下函数是一个模板,接收一个类型为 T 的容器
// 注意:类型 T 是动态的,可变的,不定的。
template <typename T>
void show(T &container)
{
    // 利用 auto 动态获取未知类型容器的相关数据
    auto it = container.begin();
    ...
    ...
}

函数默认参数

C++允许一个函数的参数有默认值,例如:

// 函数的声明
// 右侧的参数 b 如果没有传递,则默认值为3.14
void f(int a, float b = 3.14);

int main()
{
	// 显式给 b 传递参数1.23
    f(100, 1.23);

	// 使用 b 的默认值3.14
    f(200);
}

语法要点

  • 为了防止出现二义性,具备默认值的参数只能位于参数列表的最右边
  • 如果函数定义与函数声明不在同一文件,一般只为声明指定默认参数,定义处不写默认参数

http://www.kler.cn/a/561797.html

相关文章:

  • 编写一个程序,计算并输出1到100的和(Python版)
  • <02.25>Leetcode100
  • DeepSeek-R1技术全解析:如何以十分之一成本实现OpenAI级性能?
  • 全方位监控AWS Application Load Balancer异常情况实战
  • 基于GO语言的车牌识别api技术-港澳车牌文字识别
  • 微软开源神器OmniParser-v2.0本地部署教程
  • git | 团队协作开发注意事项
  • 【Blender】三、材质篇--01,Blender材质基础 原理化BSDF
  • 大模型输出markdown格式前端对话框
  • 深入理解C++ 线程池:动手实践与源码解析
  • 是德科技keysight N5173B信号发生器,是一款经济高效的仪器
  • Java多线程中的死锁问题
  • Docker 部署 Jenkins持续集成(CI)工具
  • Java23种设计模式案例
  • smolagents学习笔记系列(五)Tools-in-depth-guide
  • 804 唯一摩斯密码词
  • 【leetcode hot 100 1】两数之和
  • 钉钉合同审批对接腾讯电子签,实现合同全流程自动化管理
  • 【删边问题——Tarjan求割边】
  • 宿主机的 root 是否等于 Docker 容器的 root?