C++中的函数新特性
发布日期:2022-02-07 06:39:44 浏览次数:5 分类:技术文章

本文共 3267 字,大约阅读时间需要 10 分钟。

C++中的函数新特性(1)

大纲:

1. 内联函数
2. 函数重载
3. 函数形参默认值
4. 初涉函数模板

先来速成新特性

1. 内联函数

说到内联函数,不得不提和它类似的一个东西先

#define F(x) ((x)*(x))

没错,就是宏定义

在程序编译过程中,F(x)会自动替换成((x)*(x))
从而在程序中F(x)就像一个函数一样

C++中当然也有宏定义

不过有一个新特性
能够得到与此类似的实现

inline int F(int x){    return x*x;}
  1. 语法:和普通函数的定义几乎一模一样,不过就是在声明语句前面加了一个词

    inline

  2. 作用:和宏定义类似,在函数调用的地方,

    编译器将会使用相应的函数代码替换函数的调用
    也就是在编译阶段就替换代码
    实际运行的时候已经没有函数调用了
    这一点是和宏定义类似的

2. 函数参数默认值

在C++的函数中,我们可以在声明的时候添加默认值

语法简介

放码过来 展示下语法

如下面
这是函数原型:

int function(int a = 2)

这是函数定义:

int function(int a){    return a*a;}

然后在调用函数的时候,我们可以这样

function(6);//返回36function(4);//返回16function();//返回4

嗯??第三条语句并没有传递参数呀?

在没有传递参数的时候

函数会自动采用在声明时使用的默认值

3. 函数重载

C++中,是允许同名函数的存在的

在调用函数的时候,
会根据函数的形参列表选择其中一个执行
所谓函数重载便是如此

例:我们可以定义这样一组函数

void print(int a);void print(int a,int b);void print(double a);void print(int a, double b);void print(doubla a, int b);

然后我们在调用函数的时候

print (3);// 调用第一个print (3,4); //调用第二个print (3.0); //调用第三个print (3,2.0); //调用第四个print (2.0, 2); //调用第五个

这几个调用都会调用不同的函数

4. 函数模板

如果我要打一个交换两个int变量的函数

我可以这样

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

如果我还要打一个交换double变量的呢?

如果我还要交换long变量呢?
我是不是都要打一个swap函数!!
好烦!!
函数模板,就是为了解决你这样的烦恼而来
且看下面

template 
void swap(T & a, T & b){ T temp; temp = a; a = b; b = temp;}

关键字:template(模板)

关键字:typename

第一行,指出这是一个函数模板

一个可替代的变量类型,我们暂且命名为T
然后后面函数的定义
就用T来代替具体的类型
之后我们的函数调用
就可以用这一个swap函数,去交换int变量
去交换double变量

实际上函数模板就是在编译的时候

将T换成所需要的类型
就像 typedef T int ;一样

下面是一些比较细的注意事项

最好边看边打码边实践

1. 内联函数

为什么我们需要内联函数

1. 为了效率

函数的调用原理

函数调用时
需要程序在运行时跳到调用函数所在地址
然后执行函数后,跳回上一级并且返回值
在这一跳一跳的过程
需要做很多事情

宏定义和内联函数

都通过直接替换代码的做法
避免了常规的函数调用
节省了计算资源和存储空间

2. 为了避免宏定义的弊端

#define F(x) ((x)*(x))

就如同这条宏定义

为什么要加这么多括号呢?
(希望能够自己思考一下)

如果不加

当我们使用F(x+1)
宏定义会替换成 x+1 * x+1
明显不能算出我们所期待的x+1 的平方

再如,如果在含有这条宏定义的程序中

我们这样
F(c++);
又会发生什么呢?

替换后会变成

c++ * c++
结果不好确定
而且c还被加了两遍
一定不会是自己所期望自己的结果
返回c的平方后c++;

这些种种弊端,内联函数都不存在

只管当普通函数用就好啦

使用内联函数的注意事项

  1. 被调用多次且短小的程序适合作为内联函数
  2. 只被调用一两次,或者函数定义代码比较长,不适合用内联函数
  3. !! 内联函数不能递归

2. 函数参数默认值

两个注意事项

  1. 从右向左添加默认值
  2. 默认值只加在函数原型,函数定义中不用加参数默认值
    下面我解释一下上面的两句话

1. 从右向左添加默认值

假设有这样的一个函数原型

int function (int a, int b = 3, int c )
我这样调用
function(2,4);
这是想做什么呢?
是因为b有了默认值,想只给a和c赋值吗?
但是

实参按从左向右的顺序依次赋给对应的形参

也就是说
2 会赋给 a , 4 会赋给 b,
不会跳过默认值

不过,我们可以这样修改函数原型

int function (int a, int c , int b = 3)
这样就没有问题了

所以,默认值从右往左添加

2. 只有函数原型需要加默认值

这个注意事项相信大家再看会该节开头的例子就懂了

这是函数原型:

int function(int a = 2)

这是函数定义:

int function(int a){    return a*a;}

3. 函数重载

函数特征标

先明白一个概念:函数的特征标

函数特征标

对于相同名字的函数
函数的特征标由函数定义的形参列表决定
例:
int function (int , int );
int function (double );
第一个函数的形参列表为(int, int)
第二个函数的形参列表为(double)
所以虽然相同名字,这是两个不同的函数

成功重载的条件

const可以重载吗

void print(int a);void print (const int a);

这个是不可以的,

void print (int & a);void print (const int & a);

这个是可以的

void print (int * a);void print (const int * a);

这个也是可以的

我其实很想解释解释为什么可以为什么不可以的

然后发现我不会解释
不过在DEV上亲测过

引用变量能重载吗

void print (int a);void print (int & a);

这两个是无法重载的

二义性与类型转换

假设这里定义了这样的函数

void print (int a, double = 3);
void print (int b);
这两个当然是不同的函数,当然可以重载
可是,如果我这样调用函数
print(3);
对于第一个版本,当然可以使用,因为第二个参数默认为3,可以省略
对于第二个版本,毫无疑问可以使用
这下子怎么办????
编译器就会报错
这就叫做具有二义性

二义性是指

访问同名成员的不确定性
包括访问函数,访问类成员。。。

在类型转换中,同样可能会有二义性

例子:这里定义了这几个函数

void print (int a);void print (double a);

然后

unsigned int u = 3;print(u);

会发生什么?

这里没有一个函数与u匹配,

因此u会尝试类型转换从而匹配
u既可以转为int类型也可以转为double类型
出现二义性
编译器无法确定
报错。。。。。

函数模板

明天再细写函数模板吧

真是一个大坑……

转载地址:https://blog.csdn.net/wyfwyf12321/article/details/54647617 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:C++中的新特性:引用
下一篇:稍微深入函数模板

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2024年03月11日 20时44分13秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

deepin linux 2014安装,2014.2版本的Deepin虚拟机安装浅谈(就是深度Linux) 2019-04-21
android 限速工具,Android下载器之限速篇 2019-04-21
html刷新ajax实现原理,AJAX的原理—如何做到异步和局部刷新 2019-04-21
html中列表菜单加文字请选择,html中下拉菜单 2019-04-21
读书郎平板中android,读书郎学生平板电脑怎么用 使用方法详解【图文】 2019-04-21
html5 调用摄像头 支持IE,JS调用本地摄像头拍照(兼容各大浏览器及IE8+) 2019-04-21
rust和gta5哪个吃配置_盘点4款Steam“自由度”很高的游戏,GTA5众所周知,目前最热门... 2019-04-21
es审计日志_elasticsearch 事务日志translog 2019-04-21
dw1510_超低温种子储存柜 2019-04-21
文件未找到mathpage.wll_解决MathPage.wll文件找不到的问题(找了好久的良心之作)... 2019-04-21
广州刷脸支付骗局_刷脸支付是骗局?那可能你还不了解刷脸支付 2019-04-21
java 远程调试 端口_JAVA远程调试 2019-04-21
java 使用或覆盖了已过时的api_JAVA使用或覆盖了已过时的 API 2019-04-21
java 图片旋转保存_Java 对图片90度旋转 2019-04-21
用java实现文学研究助手_数据结构文学研究助手 C语言代码实现(带源码+解析)... 2019-04-21
java gc的几种方式_GC 的三种基本实现方式 2019-04-21
wget linux java 32_通过wget在Linux上下载Java JDK会显示在许可证页面上 2019-04-21
babylonjs 设置面板位置_babylonjs 空间坐标转为屏幕坐标 2019-04-21
oracle里面如何查询sqlid,CSS_oracle中如何查看sql, --查询表状态:  select uo.O - phpStudy... 2019-04-21
oracle 查询中用case,oracle case when 在查询时候的用法。 2019-04-21