Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C++函数论

C++函数论

作者头像
Cloudox
发布于 2022-01-07 12:54:24
发布于 2022-01-07 12:54:24
34700
代码可运行
举报
文章被收录于专栏:月亮与二进制月亮与二进制
运行总次数:0
代码可运行

关于C++的函数有很多知识,因为其函数有多种变体,可以说C++创作者为了开发方便,打开了很多个后门让编程人员随心所欲地炫技使用,但私以为这也造成了使用函数时的复杂度,如果真的在代码中使用各种变体,虽然确实可以让代码看上去简洁高级,但是对于代码阅读来说却并不是特别友好。

不过,无论如何,C++提供了很多可能,这里也稍微总结一下其函数的各种变体。

定义常规函数

定义函数最简单也最常见,就是定义最常规的函数,有返回值类型、函数名、参数类型、参数名和代码块:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void swap (int a, int b) {
  int temp = a;
  a = b;
  b = temp;
}

这种函数定义只要是程序员就会熟悉了,不多说。

函数原型

什么是函数原型?为什么要用原型?

看过c/c++代码的人都知道,其代码大都有个main函数,而且一般都放在最前面,而其余自定义的函数都放在后面,这就导致如果你要在main函数中调用一个自定义函数,此时因为你的自定义函数是在后面定义的,编译器不懂你的调用语句,因此我们需要在main函数之前声明一个函数原型,表明函数的返回值类型、函数名、参数类型、参数名,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void swap (int a, int b);

int main (void) {
  int a = 1;
  int b = 2;
  swap (a, b);
  return 0;
}

void swap (int a, int b) {
  int temp = a;
  a = b;
  b = temp;
}

值得一提的是,函数原型中的参数名其实可以不用写,因为只有参数类型和数量才是函数的标志,毕竟都只是个带好罢了。

参数传递方式

参数传递方式是什么意思?这里我们指的是传递的到底是变量的拷贝还是变量本身。

如上述swap函数那样的,其实是在调用函数时拷贝了一份变量,因此在函数内随意改变参数变量值,原本的变量都不会变的。

但是我们也可以直接传递原本的变量本身,这可以通过传递指针或者变量引用来做到:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 指针
void swap (int * a, int * b);

// 引用
void swap (int & a, int & b);

指针会传递变量的地址,引用故名思议也就是传递原变量的一个引用,因此都是指向原变量的,因此这样在函数内修改变量值的话,原变量是会跟着改变的,如果不想改变,可以用const来修饰参数。

函数指针

其实和变量一样,函数也是可以有指针的,创建方法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int pam (int);
int (*pf) (int);
pf = pam;// pf 就指向了函数pam,同样的用*pf来调用函数

这个知识点其实用的并不多。

内联函数

内联函数并不是一种函数变体,而是指编译器的处理方式不同。

普通的函数调用是遇到函数调用时,将跳到函数代码的地址去,执行后返回原地址,而内联函数在编译时会直接编译到调用的代码中去,因此无需做跳转,因此内联函数的运行速度比常规函数稍快,但代价是需要占用更多的内存。显然,内联函数不能递归,否则就是无限地内联去插入代码了。

要定义为内联函数,直接省略原型,将整个定义放上去,并在函数定义前加上关键字inline:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
inline double square (double x) { return x * x; }

// 在C语言下使用宏来实现:
#define SQUARE (X) X*X

默认参数

和python一样,c++允许给函数的参数设置默认值,如果在调用时没有给对应参数赋值,那么函数将使用默认值,方法其实就是在声明函数原型时同时声明参数的默认值:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void add (int a, int b = 5);

int main() {
  int a = 1;
  add(a);
  return 0;
}

要注意的是有默认值的参数必须全部在右边,这也是为了调用时方便参数的设置,因为在调用时你要写参数,不可能参数空一个不写,而写完了你要设置的,剩下的就都是右边默认的了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int func1 (int n, int m = 4, int j = 5); // 有效
int func2 (int n, int m = 6, int j); // 无效

// 不允许这样调用:
func(1, , 2);// 无效

函数重载

c++允许有多个同名函数,只要其参数的类型或者数量不一样就可以了。

比如你可以有同样的名为swap的函数,有的参数是int类型,有的参数是double类型,有的有三个参数,等等,这些c++会认为是不同的函数,在你调用时视你传递的参数类型会自动调用对应函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void swap (int a, int b);
void swap (double a, double b);
void swap (int a, int b, int n = 5);

但是只有参数的类型和数量才是函数的特征标,仅仅返回类型不同的同名函数是不行的,必须在参数上有不同。

这还有一个名字,叫多态,有没有熟悉一点了。

函数模板

为了炫技,c++又定了函数模板这种幺蛾子,它定义一种通用函数,函数的实现方法一致,但是不限死参数类型,也就是说同一个函数,你传的参数可以是int型,也可以是double型。注意,这和上面的函数重载是有区别的,实际上也是进一步节省了函数重载的工作,不用定义那么多相同名字参数不同的函数,写那么多代码,只写一个就行了,参数类型根据传递进来的而定,即参数可配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 函数原型
template <class Any> // or typename Any
void Swap (Any &a, Any &b);

// main函数

// 函数定义:
template <class Any> // or typename Any
void Swap (Any &a, Any &b) {
  Any temp;
  temp = a;
  a = b;
  b = temp;
}

注意这里参数类型用Any代替了,也就是说你既可以传int也可以传double等等,随你传,反正结果就是交换两个变量的值。

函数模板也是可以重载的,这里既然参数的类型是不定的,但是你可以改变参数数量呀,而且也不要求所有参数类型都是布丁,可以有部分是定死的,这样就可以玩出无数花样来了,比如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template <class Any> // or typename Any
void Swap (Any &a, Any &b);// 注意这里是传递的变量引用了

template <class Any> // or typename Any
void Swap (Any &a, Any &b, int c);

真是套路多。

显示具体化

上面的函数模板让所有的参数类型使用同一个函数代码块执行同一种操作,如果我这时候又想对某个特定类型做不同的操作怎么办?就你名堂多。

一种方法是使用函数重载。

另一种方式就是显示具体化:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct job {
  // 假设有一个job结构体
}

// 普通的函数模板
template <class Any> // or typename Any
void Swap (Any &a, Any &b);

// job特供版
template <> void Swap<job> (job &, job &);

然后在job特供版的函数你自己就可以去玩出花了。

编译器到底用哪个函数版本?

上面说了这么多种函数,可能在函数原型部分我有一大堆同名但是各个细节部分不同的函数原型,当在代码中调用的时候到底编译器怎么判断用哪个呢?换言之也就是这些调用是怎么排序的呢?

从最佳匹配到最差匹配顺序如下:

  1. 完全匹配,但常规函数优先于模板。
  2. 提升转换(需要转换参数类型,如char和shorts自动转换为int,float自动转换为double)。
  3. 标准转换(需要转换参数类型,如int转换为char,long转换为double)。
  4. 用户定义的转换,如类声明中定义的转换。

目前学习到了这些函数变体,如有其它,继续补充。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017.12.01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Windows安装Redis
下载地址:Releases · microsoftarchive/redis (github.com)
kenvie
2022/04/29
6890
Windows安装Redis
Windows安装Redis
下载地址:https://github.com/microsoftarchive/redis/tags
乐心湖
2020/07/31
6740
Windows安装Redis
vscode高效管理不同项目文件
vscode可以在Terminal中通过指令 code 执行,经查阅发现 code -n ProjectFolder 可以打开对应的项目文件夹,然后将 code -n ProjectFolder 根据编程语言进行重命名,并加入系统环境变量中。最终效果如下:
用户9282069
2021/12/13
1.4K0
Redis的安装 – Windows
要使用Redis,首先我们需要知道Redis是个什么东西(当然,需要使用Redis的,一般情况下也会对Redis有一些了解了)。
Yiiven
2022/12/15
7010
Redis的安装 – Windows
Redis——Windows安装
本篇只谈安装,后续会深入讲解Redis,比如它的内存管理,快照,订阅等待。针对不同的用户,Redis有Windows和Linux两种环境安装, 官网上下的是Statble版是Linux,大家一定要注意。由于本人做本地端,所以以下谈的是Windows安装。
全栈程序员站长
2022/07/22
7470
Redis——Windows安装
Windows安装Redis
在Windows本地服务管理里面,可以看到已经注册并启动了Redis服务,服务执行命令如下:
十毛
2019/06/15
1.8K0
windows下配置redis
https://github.com/MicrosoftArchive/redis/releases
I Teach You 我教你
2023/07/18
2160
windows下配置redis
Windows下安装并设置Redis
Redis对于Linux是官方支持的,安装和使用没有什么好说的,普通使用按照官方指导,5分钟以内就能搞定。详情请参考: http://redis.io/download 但有时候又想在windows下折腾下Redis,可以从redis下载页面看到如下提示: Win64 Unofficial The Redis project does not directly support Windows, however the Microsoft Open Tech group develops and mai
庞小明
2018/03/07
9090
全网最完整的Redis入门指导
本文提供全网最完整的Redis入门指导教程,下面我们从下载Redis安装包开始,一步一步的学习使用。
Kiba518
2020/06/16
9660
Windows下安装并设置Redis
Redis对于Linux是官方支持的,安装和使用没有什么好说的,普通使用按照官方指导,5分钟以内就能搞定。详情请参考: http://redis.io/download 但有时候又想在windows下折腾下redis,可以从redis下载页面看到如下提示(在页面中搜索 "windows"): [plain] view plain copy Win64   Unofficial  The Redis project does not directly support Windows,        howe
小小明童鞋
2018/06/13
9710
Redis系统学习之Windows安装
Windows下安装 下载安装包 下载地址:https://github.com/microsoftarchive/redis/releases 选择自己想要的版本点击zip下载 下载完成后会得到一个
彼岸舞
2021/05/07
2790
Redis系统学习之Windows安装
redis在window环境下的安装教程
进入这个网址,下载window版本https://github.com/microsoftarchive/redis/releases
GeekLiHua
2025/01/21
3910
redis在window环境下的安装教程
Redis下载和安装(Windows系统)
虽然 Redis 官方网站没有提供 Windows 版的安装包,但是,微软开发并维护了针对Win64的Windows版本。
777nx
2023/12/27
1.3K0
Redis下载和安装(Windows系统)
Windows配置Redis数据库服务的方法
  本文介绍在Windows电脑中,下载、安装、部署并运行Redis数据库服务的方法。
疯狂学习GIS
2024/09/20
1740
Windows配置Redis数据库服务的方法
Redis的安装以及使用入门
Redis的安装以及使用入门 Redis是一个用的比较广泛的Key/Value的内存数据库,新浪微博、 Github、StackOverflow?等大型应用中都用其作为缓存,Redis的官网为htt
bering
2019/12/02
8060
windows下部署sentinel模式的Redis主从集群
在前面一篇文章中,我介绍了如何在windows下安装普通的redis主从,也介绍了主从模式下的问题,那么本文就介绍Redis集群中一种更优的模式,Sentinel模式。
诺浅
2020/08/20
7120
windows 安装 redis 详细步骤
https://github.com/microsoftarchive/redis
很酷的站长
2023/02/02
4.8K0
windows 安装 redis 详细步骤
redis及php扩展配置(windows+php5)
redis及php扩展配置(windows+php5) redis及php扩展配置windowsphp5 安装 启动 安装php扩展 编写测试代码 1. 安装 redis官方github链接:https://github.com/antirez/redis redis官方默认没有windows版本,微软提供的一个版本:https://github.com/MicrosoftArchive/redis 文件说明: redis-server.exe:服务程序 redis-check-dump.exe:本
csxiaoyao
2018/05/11
1.1K0
win10下Redis安装、启动教程
然而,当你尝试了之后会发现,这个下载速度实在是太慢了。小编提供一种简单的下载方式。关注小编公众号 未名编程,回复关键词 Redis安装包 即可下载。
未名编程
2024/10/12
4710
win10下Redis安装、启动教程
Windows 使用 Alias,高效办公指南!
类 Unix 系统中的 Alias,为一段功能命令设置一个别名,然后利用该别名去调用该功能,以此来提升工作效率
AirPython
2022/09/28
4.3K0
Windows 使用 Alias,高效办公指南!
相关推荐
Windows安装Redis
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验