C++基础:第七章 函数

第七章 函数

第1节 函数基础

栈帧结构
在这里插入图片描述

在这里插入图片描述

函数的外部链接

第2节 函数详解

传值、传址、传引用

传参数时的类型退化,传数组时函数形参退化成指针,所以形参不要写数组个数

多维数组作为函数参数时

void fun(int (*par)[4])

int a[3][4] = {0};
fun(a);
避免退化的写法
void fun(int (&par)[3])
    
int a[3];
fun(a);
变长参数
  • initializer_list ,变量类型必须相同

    #include <initializer_list>
    void fun(std::initializer_list<int> par)
        
    fun({1,2,3,4,5});
    
  • 可变长度模板参数 (不限制类型相同,复杂一些)

  • 使用省略号表示形参(不建议使用)

函数缺省实参

void fun (int x = 0){} fun();

缺省实参右侧的参数都必须有缺省实参

传入实参时从左到右与形参匹配

在一个翻译单元中,每个参数的缺省实参只能定义一次

缺省实参为对象时,实参的缺省值会随对象的值变化而变化 (不建议,阅读困难)

推荐方法:源文件中定义函数,头文件中声明函数同时定义缺省实参,main函数中调用函数,最安全。

main函数的两个版本
  • 无形参 int main(){}
  • 带两个形参的 int main(int argc,char* argv[]){}

argc 为非负数,程序运行环境传递给程序的实参个数

argv为指针,指针指向argc+1个指针的数组

函数体

函数体形成域

  • 其中包含自动对象
  • 可包含局部静态对象

函数体的返回值

  • 隐式返回 void
  • 显式返回 return

返回值优化(RVO)

返回类型

表示函数计算结果类型,可以为void

返回类型的几种书写方式

  • 经典:位于函数头前部

  • 11引入新方法:位于函数头的后部

    auto fun(int a,int b) -> int
    {
        return a + b;
    }
    
  • 14引入方式:返回类型自动推导

17引入返回类型的结构化绑定

第3节 函数重载与重载解析

(重载的函数,参数类型不相同)

int fun(int x){
    return x+1;
}
double fun(double x){
    return x+1;
}
fun(3);
fun(3.5);

使用相同的函数名定义多个函数,每个函数具有不同的参数列表

  • 不能基于不同的返回类型进行重载
  • 函数重载与mangling

编译器如何选择正确的版本完成调用

名称查找

限定查找(限定查找域)与非限定查找

非限定查找会进行逐级域查找——名称隐藏(同一域的函数在域内会隐藏其他域的同名函数)

查找通常会在已声明集合中进行

实参依赖查找

namespace MyNS{
    struct Str{};
    void g(Str s){
        
    }
}
MyNS::Str obj;
g(obj);
重载解析

在名称查找基础上进一步选择合适的调用函数

  • 过滤不能被调用的版本

    • 参数个数不对
    • 实参无法转换为形参
    • 实参不满足形参的限制条件
  • 在剩余版本中查找最匹配的版本,匹配级别越低越好(同一匹配级别视为重定义)

    1. 完美匹配,平凡转换(加const)

    2. promotion或加平凡转换

    3. 标准转换或标准平凡转换

    4. *自定义转换

    5. *调用形参为省略号的版本

  • 函数包含多个形参时,所选函数的所有形参的匹配级别都要优于或等于其他函数

第4节 函数相关的其他内容

递归函数

在函数体内调用其自身的函数

通常用于描述复杂的迭代过程(注意避免无线递归)

内联函数

调用函数时,函数体运算较简单,则较多资源用于构建和释放栈帧,针对这一问题编译期可以展开函数,避免构建栈帧。

inline内联标识符,向编译器发出请求,将函数编译时展开

inline内联标识符,将程序级的一次定义原则改为翻译单元级别的一次定义原则

向编译器发出请求,将函数编译时展开

constexpr函数与consteval函数

为了让**某些函数在编译期计算**,引入constexpr函数

(内联函数和constexpr函数都应该定义在头文件中,翻译单元级不重复)

constexpr int fun(int x){
    return x + 1;
}

constexpr int y = 3;
int z = fun(y);

实参也需要是字面值或常量编译表达式

函数指针

函数类型与函数指针类型

int fun(int x){} 函数类型为int(int)

using K = int(int);
K fun;           //相当于函数声明,不可用于定义

或者配合std::function使用

(函数指针多数跟高阶函数配合使用)

函数指针与重载

函数指针作为参数

using K = int(int);
void pla(K* input) {  
	std::cout << (*input)(2) << std::endl;
}

int inc(int x) {
	return x + 1;
}

int main(int argc, char *argv[]) {
	pla(inc);
}

函数指针作为返回值

int inc(int x){
    return x+1;
}
int dec(int x){
    renturn x-1;
}
auto fun(bool input){
    if(input)
        return inc;        //返回函数指针
    else
        return dec;
}

std::cout<<(*fun(true))(100)<<std::endl;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sdhdwyx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值