首页 > 其他分享 >二十、函数(三)

二十、函数(三)

时间:2023-12-12 23:45:20浏览次数:37  
标签:return 函数 二十 int float ave type1

二十、函数(三)

1、函数重载

函数重载技术运行我们创建函数名称相同的函数,但是为了编译器能够正确的编译这个程序,这些函数需要采用不同的参数列表来区分(即函数名相同,参数类型不同)。C语言中无法进行函数重载

1)项目设计

①设计一个函数,能够使得函数求出两个int值的平均值

②设计一个函数,能够使得函数求出三个int值的平均值

③设计一个函数,能够使得函数求出三个float值的平均值

//不使用函数重载实现上述功能
#include <iostream>

int Ave_1(int a, int b)
{
    return (a + b) / 2;
}

int Ave_2(int a, int b, int c)
{
    return (a + b + c) / 3;
}

float Ave_float(float a, float b,float c)
{
    return (a + b + c) / 3;
}

int main()
{
    std::cout << Ave_1(2, 3) << std::endl;
    std::cout << Ave_2(2, 3, 4) << std::endl;
    std::cout << Ave_float(2.2, 3.3, 4.4) << std::endl;
}
//使用函数重载实现上述功能
#include <iostream>

int Ave(int a, int b)
{
    return (a + b) / 2;
}

int Ave(int a, int b, int c)
{
    return (a + b + c) / 3;
}

float Ave(float a, float b, float c)
{
    return (a + b + c) / 3;
}

int main()
{
    std::cout << Ave(2, 3) << std::endl;
    std::cout << Ave(2, 3, 4) << std::endl;
    std::cout << Ave(2.2f, 3.3f, 4.4f) << std::endl;
}

2)尽管函数名称相同,但是再我们调用函数时,是通过函数参数的不同,编译器还是能够确定我们调用的是哪一个函数,因此函数能够准确的编译。但是编译器无法单纯的通过返回值确定你要返回的函数,比如

float Ave(int a,intb)和int Ave(int a,int b)是无法重载的

3)思考如下两个函数能否重载

/*不允许重载,因为数组也相当于指针
#include <iostream>

int Ave(int* pa, int count)
{
    return 0;
}

int Ave(int pa[], int count)
{
    return 0;
}
*/
//以下情况也不允许重载,编译不报错,但是使用函数时报错
#include <iostream>

int Ave(int& a, int& b)  //传入引用参数
{
    return (a + b) / 2;
}

int Ave(int a, int b)
{
    return (a + b) / 3;
}

int main()
{
    int a = 100;
    int b = 100;
    //std::cout << Ave(a, b) << std::endl;   //报错
    std::cout << Ave(2, 3) << std::endl; //不出错,临时的常量不存在引用,所以
}


//以下情况也不允许重载
#include <iostream>
int ave(int& a, int& b)
{
    return a + b;
}
float ave(float a, float b)
{
    return a * 2 + b;
}

int main()
{
    char a{ 100 }, b{ 200 };
   //std::cout << ave((int)a, (int)b)<< std::endl;  //转化后的int类型的a和b是一个临时的变量,而临时变量没有引用,即没有固定的内存地址,所以无法转化
}
//无法重载
#include <iostream>

int ave(int a, int b)  //参数为变量
{
    return a + b;
}
int ave(const int  a, const int b)  //参数为常量
{
    return a * 2 + b;
}

int main()
{
    int a{ 100 }, b{ 200 };  //不管a和b是什么类型,都无法影响到函数中的值的变化,因为传递的是值

    //std::cout << ave(a,b)<< std::endl;    //编译报错,因为传递的是值
}
//可以重载
#include <iostream>

int ave(int& a, int& b)  //参数为变量的引用
{
    return a + b;
}
int ave(const int&  a, const int& b)  //参数为常量的引用
{
    return a * 2 + b;
}

int main()
{
    int a{ 100 }, b{ 200 };  
    std::cout << ave(a,b)<< std::endl;    //实现了重载,调用的是参数为变量的引用的函数
    const int c{ 100 }, d{ 200 };
    std::cout << ave(c, d) << std::endl; //实现了重载,调用的是参数为常量的引用的函数
}
//不可以重载
#include <iostream>

int ave(int a=150, int b=250)  //函数有默认参数
{
    return a + b;
}
int ave(float a=300.0f, float b=150.0f)  //函数有默认参数
{
    return a * 2 + b;
}

int main()
{
    //std::cout << ave() << std::endl;    //编译出错,因为直接调用ave(),不带参数,无法确定到底调用哪个函数
}
2、函数模板

1)引出函数模板:统一一个函数模板将功能系相同参数不同的函数统一表示

int ave(int a,int b, int c)
{
    return (a+b+c)/3;
}
float ave(float a,float b,float c)
{
    return (a+b+c)/3;
}

//int  ave(int a,int b,int c)和float ave(float a,float b,float c)除了类型不同外,函数的运算逻辑都一样,这样的函数可以利用函数模板技术来生成对应的函数

2)函数模板语法

//函数模板语法
template <typename type1>type1 ave(type1 a,type1 b)
{
    return (a+b)/2;
}

int a=ave(1,2); //ave相当于int ave(int a,int b);
char =ave(1,2); //ave相当于char ave(char a,char b;)
//函数模板定义及用法
#include <iostream>

template <typename type1>type1 
ave(type1 a, type1 b, type1 c)  //定义一个函数模板type1,可支持各种类型
{
    return a + b + c;
}

int main()
{
    std::cout << ave(100, 200, 300) << std::endl;
    std::cout << ave(100.1f, 200.2f, 300.3f) << std::endl;
    std::cout << ave((char)100, (char)200, (char)300) << std::endl;
}

3)函数模板类型参数

//可以将type1当作一种类型,可以用来声明变量
#include <iostream>

template <typename type1>type1
ave(type1 a, type1 b, type1 c)  //可以把type1当作一种类型
{
    type1 x = a;   //可以通过type1申明变量
    return a + b + c + x;
}

int main()
{
    std::cout << ave(100, 200, 300) << std::endl;
    std::cout << ave(100.1f, 200.2f, 300.3f) << std::endl;
    std::cout << ave((char)100, (char)200, (char)300) << std::endl;
}

4)指定函数模板参数

//显示的为函数模板指定一个类型
template <typename type1>type1 ave(type1 a,type1 b)
{
    return (a+b)/2;
}

ave<int>(192.0f,153,1f);  //相当于执行int ave(int a,int b);而不是float ave(float a,float b);
#include <iostream>

template <typename type1>type1
ave(type1 a, type1 b, type1 c)  
{
    type1 x = a;   
    return a + b + c + x;
}

int main()
{
    std::cout << ave(100, 200, 300) << std::endl;
    std::cout << ave<int>(100.1f, 200.2f, 300.3f) << std::endl;   //强制指定函数模板参数,所有参数一律使用int
    std::cout << ave((char)100, (char)200, (char)300) << std::endl;
}

5)指针在函数模板中常见的问题

#include <iostream>

template <typename type1>type1
bigger(type1 a, type1 b)
{
    return a > b ? a : b;
}

int main()
{
    int a{ 100 };
    int b{ 200 };
    int c{};
    c = *bigger(&a, &b); //此处将a和b的地址传入了函数模板,比较的是a和b的地址,而不是a和b的值
    std::cout << c << std::endl;   //输出100,因为a的地址大于b的地址
}
3、函数模板和重载

1)函数模板的例外处理

//通过template<>定义一种函数模板的例外情况
template <typename type1>type1 ave(type1 a,type1 b)
{
    return (a+b)/2;
}
template <>float ave(float a,float b)
{
    return (a+b-100.0f)/2;
}

//函数模板例外处理用法
#include <iostream>

template <typename type1>type1
bigger(type1 a, type1 b)
{
    return a > b ? a : b;
}

template <>                       //定义一种例外情况
int* bigger(int* a, int* b)
{
    return *a > *b ? a : b;
}

int main()
{
    int a{ 100 };
    int b{ 200 };
    int c{};
    c = *bigger(&a, &b);  //用指针来传递参数
    std::cout << c << std::endl;   
}
//注:此种方法只是定义了int类型指针的情况

2)函数模板和函数重载

int ave(int a,int b)
{
    return a+b;
}
template <typename type1>type1 ave(type1 a,type1 b)
{
    return (a+b)/2;
}
//函数重载执行顺序优先于函数模板
//函数重载执行顺序优先于函数模板
#include <iostream>

template <typename type1>type1
bigger(type1 a, type1 b)
{
    return a > b ? a : b;
}

int bigger(int a, int b)
{
    return a > b ? a : b;
}

float* bigger(float* a, float* b)
{
    return *a > *b ? a : b;
}

int main()
{
    int a{ 100 };
    int b{ 200 };
    int c{};
    c = bigger(a, b);  //用指针来传递参数
    std::cout << c << std::endl;
}

3)函数模板的重载

//函数模板的重载也是通过参数来区分的
#include <iostream>

template <typename type1>type1
ave(type1 a, type1 b)          //函数模板重载,2个参数
{
    return a+b;
}

template <typename type1>type1
ave(type1 a, type1 b,type1 c)  //函数模板重载,3个参数
{
    return a+b+c;
}

int main()
{
    int a{ 100 };
    int b{ 200 };
    int c{300};
    std::cout << ave(a, b) << std::endl;
    std::cout << ave(a,b,c) << std::endl;
}
4、auto->decltype

1)atuo关键字

auto可以声明一个变量,让编译器根据变量的值来推断变量的类型,例如auto a{123};相当于int a{123};

利用auto的这一特性,可以创建一个函数

auto ave(int a,int b)
{
    return a+b;         //根据返回值确定auto的类型
}
int ave(int a,int b)
{
    return a+b;
}
//注:以上并非auto的最恰当用法,不管是函数还是变量,都不推荐使用auto来声明

2)auto关键字特性

①auto不保留const属性

const int a{};
auto b{a};  //此处的b为int类型,而不是const类型

②auto推断一个类型时,会优先推断为值类型,而非引用类型

int a{1500};
const int& la{a};  //定义一个a的引用
auto d=la;  //此处d为int类型,而不是int&

③auto利用函数返回值来确定类型的时候,函数会执行

auto ave(int a,int b)
{
    return a+b;         //根据返回值确定auto的类型
}

auto c = ave(a,b);  //c的类型依据ave()函数返回值的类型来确定

3)auto关键字和拖尾函数

//实现比较两个数,将大的数修改为500
#include <iostream>

int& bigger(int& a, int& b)
{
    return a > b ? a : b;
}

int main()
{
    int a{ 100 };
    int b{ 200 };
    bigger(a, b) = 500;
    std::cout << a << '\n' << b << std::endl;
}

因为auto会优先把值匹配成值类型,而不是引用类型,所以就上述案例,如果直接将函数的返回值设置为auto类型,达不到上述案例的效果,此时可以引用拖尾函数

//拖尾函数
#include <iostream>

auto bigger(int& a, int& b)->int&        //拖尾函数,通过->指定auto的类型
{
    return a > b ? a : b;
}

int main()
{
    int a{ 100 };
    int b{ 200 };
    bigger(a, b) = 500;
    std::cout << a << '\n' << b << std::endl;
}

4)decltype关键字

decltype关键字可以得出一个表达式的类型

//decltype语法
语法:delctype(表达式) 声明变量;     //表达式可以是

int a{100};
unsigned b{200};
decltype(a-b) x;    //相当于unsigned x; 依据a-b的类型,推断出x的类型

标签:return,函数,二十,int,float,ave,type1
From: https://www.cnblogs.com/piaolaipiaoqu/p/17898132.html

相关文章

  • 无涯教程-Java - for 语句函数
    for循环是一种重复控制结构,可让您有效地编写需要执行特定次数的循环。for-语法for(initialization;Boolean_expression;update){//Statements}for-示例以下是Java中for循环的示例代码。publicclassTest{publicstaticvoidmain(Stringargs[]){......
  • react_hooks系列 useCallback,高阶函数memo
    react_hooks的useCallback,高阶函数memo一、概念和作用1、memo高阶函数:memo解决的是函数式组件的无效渲染问题,当函数式组件重新渲染时,会先判断数据是否发生了变化。相当于类组件的PureComponent(默认提供ShouldComponentUpdate)2、useCallback:1)、useCallback会返回一个函数的memoiz......
  • 常用损失函数
    损失函数的意义衡量模型性能。损失函数提供了一种量化模型预测结果与实际结果之间差异的方法。通过这种量化,我们可以客观地评价模型的好坏。模型优化的指导。模型训练实际上是一个优化过程,目的是最小化损失函数。模型选择和调整。不同的问题可能更适合不同的损失函数。处理不......
  • C 语言函数:入门指南
    C语言中的函数声明和定义您可以通过以下方式创建并调用函数://创建一个函数voidmyFunction(){printf("我刚被执行了!");}intmain(){myFunction();//调用函数return0;}一个函数包括两个部分:声明:函数名称、返回类型和参数(如果有)定义:函数体(要执行的代码)......
  • 无涯教程-Java - while 语句函数
    只要给定条件为真(true),Java编程语言中的while循环语句就会重复执行目标语句。while-语法while(Boolean_expression){//Statements}在这里,声明可以是单个语句或语句块。条件可以是任何表达式,并且true是任何非零值。while-示例publicclassTest{publics......
  • C 语言函数:入门指南
    C语言中的函数声明和定义您可以通过以下方式创建并调用函数://创建一个函数voidmyFunction(){printf("我刚被执行了!");}intmain(){myFunction();//调用函数return0;}一个函数包括两个部分:声明:函数名称、返回类型和参数(如果有)定义:函数体(要执行的代码......
  • Java登陆第二十三天——JavaScript对象、JSON、事件
    JS中声明对象的两种格式方法1,newobject()然后依次添加属性或方法栗子:<script>//初始化对象varuser=newObject();//给对象添加属性并赋值user.name="张三";user.age=18;//给对象添加方法user.say=functi......
  • 无涯教程-Java - Non Access Modifiers函数
    Java提供了许多非访问修饰符来实现许多其他功能。static修饰符:用于创建类方法和变量的。final修饰符:用于最终确定类,方法和变量。abstract修饰符:用于创建抽象类和方法。volatile修饰符:用于线程的已同步。static(Static)修饰符Static变量static关键字用于创......
  • TS函数重载
    学习网址:学习网址:https://www.bilibili.com/video/BV1q64y1j7aH/TS函数重载functionhello(name:string):stringfunctionhello(age:number):stringfunctionhello(value:number|string):string{if(typeofvalue==='string'){return"我的名......
  • Python高级之闭包函数
    闭包函数【一】闭包函数的定义闭包(Closure)是指在函数内部定义的函数,并且这个内部函数可以访问外部函数的变量。这种机制允许函数保留对它创建时可见的变量的访问权,即使在其生命周期结束后也可以使用。闭包的主要特点是:内部函数定义在外部函数内部。内部函数可以引用外部函数......