本文共 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;}
语法:和普通函数的定义几乎一模一样,不过就是在声明语句前面加了一个词
inline
作用:和宏定义类似,在函数调用的地方,
编译器将会使用相应的函数代码替换函数的调用 也就是在编译阶段就替换代码, 实际运行的时候已经没有函数调用了 这一点是和宏定义类似的
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函数!! 好烦!! 函数模板,就是为了解决你这样的烦恼而来 且看下面templatevoid 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++;
这些种种弊端,内联函数都不存在
只管当普通函数用就好啦使用内联函数的注意事项
- 被调用多次且短小的程序适合作为内联函数
- 只被调用一两次,或者函数定义代码比较长,不适合用内联函数
- !! 内联函数不能递归
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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!