首页 / C++ / 03_C++对C函数的扩展
03_C++对C函数的扩展
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了03_C++对C函数的扩展,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6517字,纯文字阅读大概需要10分钟。
内容图文
![03_C++对C函数的扩展](/upload/InfoBanner/zyjiaocheng/650/549a1d5b1be64f3492fd0df5cf8958a7.jpg)
一:inline 内联函数
C++中的 const 常量可以替代宏常数定义,如:
const int A = 3; #define A 3
C++中是否有解决方案替代宏代码片段呢?(替代宏代码片段就可以避免宏的副作用!)
C++中推荐使用内联函数替代宏代码片段
C++中使用 inline 关键字声明内联函数
内联函数声明时inline关键字必须和函数定义结合在一起,否则编译器会直接忽略内联请求。
//宏替换和函数调用区别
#include "iostream"
using namespace std;
#define MYFUNC(a, b) ((a) < (b) ? (a) : (b))
inline int myfunc(int a, int b)
{
return a < b ? a : b;
}
int main()
{
int a = 1;
int b = 3;
//int c = myfunc(++a, b); //头疼系统
int c = MYFUNC(++a, b);
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("c = %d\n", c);
system("pause");
return 0;
}
说明 1:
必须 inline int myfunc(int a, int b)和函数体的实现,写在一块
说明 2:
C++编译器可以将一个函数进行内联编译
被 C++编译器内联编译的函数叫做内联函数
内联函数在最终生成的代码中是没有定义的
C++编译器直接将函数体插入在函数调用的地方
内联函数没有普通函数调用时的额外开销(压栈,跳转,返回)
说明 3:
C++编译器不一定准许函数的内联请求!
说明 4:
内联函数是一种特殊的函数,具有普通函数的特征(参数检查,返回类型等)
内联函数是对编译器的一种请求,因此编译器可能拒绝这种请求
内联函数由 编译器处理,直接将编译后的函数体插入调用的地方
宏代码片段 由预处理器处理, 进行简单的文本替换,没有任何编译过程
说明 5:
现代 C++编译器能够进行编译优化,因此一些函数即使没有 inline 声明,也可能被编译器内联编译
另外,一些现代 C++编译器提供了扩展语法,能够对函数进行强制内联
如: g++中的__attribute__((always_inline))属性
说明 6:
C++中内联编译的限制:
不能存在任何形式的循环语句
不能存在过多的条件判断语句
函数体不能过于庞大
不能对函数进行取址操作
函数内联声明必须在调用语句之前
编译器对于内联函数的限制并不是绝对的,内联函数相对于普通函数的优势只是省去了函数调用时压栈,跳转和返回的开销。
因此,当函数体的执行开销远大于压栈,跳转和返回所用的开销时,那么内联将无意义。
结论:
1) 内联函数在编译时直接将函数体插入函数调用的地方
2) inline 只是一种请求,编译器不一定允许这种请求
3)内联函数省去了普通函数调用时压栈,跳转和返回的开销
二:默认参数
C++中可以在函数声明时为参数提供一个默认值,当函数调用时没有指定这个参数的值,编译器会自动用默认值代替void myPrint(int x = 3)
{
printf("x:%d", x);
} 函数默认参数的规则
只有参数列表后面部分的参数才可以提供默认参数值
一旦在一个函数调用中开始使用默认参数值,那么这个参数后的所有参数都必须使用默认参数值 //默认参数
void printAB(int x = 3)
{
printf("x:%d\n", x);
}
//在默认参数规则 ,如果默认参数出现,那么右边的都必须有默认参数
void printABC(int a, int b, int x = 3, int y=4, int z = 5)
{
printf("x:%d\n", x);
}
int main62(int argc, char *argv[])
{
printAB(2);
printAB();
system("pause");
return 0;
}
三:函数占位参数
/*
函数占位参数
占位参数只有参数类型声明,而没有参数名声明
一般情况下,在函数体内部无法使用占位参数
*/
int func(int a, int b, int )
{
return a + b;
}
int main01()
{
//func(1, 2); //可以吗?
printf("func(1, 2, 3) = %d\n", func(1, 2, 3));
getchar();
return 0;
}
四:默认参数和占位参数
/*
可以将占位参数与默认参数结合起来使用
意义
为以后程序的扩展留下线索
兼容 C 语言程序中可能出现的不规范写法
*/
//C++可以声明占位符参数,占位符参数一般用于程序扩展和对 C 代码的兼容
int func2(int a, int b, int = 0)
{
return a + b;
}
void main()
{
//如果默认参数和占位参数在一起,都能调用起来
func2(1, 2);
func2(1, 2, 3);
system("pause");
}
结论: //如果默认参数和占位参数在一起,都能调用起来
五:函数重载(Overroad)
1. 重载概念
(1) 函数重载概念
函数重载(Function Overload)
用同一个函数名定义不同的函数
当函数名和不同的参数搭配时函数的含义不同
(2)函数重载的判断标准
/*
函数重载至少满足下面的一个条件:
参数个数不同
参数类型不同
参数顺序不同
*/
(3) 函数返回值不是函数重载的判断标准
实验 1:调用情况分析;实验 2:判断标准
//两个难点:重载函数和默认函数参数混搭 重载函数和函数指针
/*
int func(int x)
{
return x;
}
int func(int a, int b)
{
return a + b;
}
int func(const char* s)
{
return strlen(s);
}
int main()
{
int c = 0;
c = func(1);
printf("c = %d\n", c);
c = func(1, 2);
printf("c = %d\n", c);
c = func("12345");
printf("c = %d\n", c);
printf("Press enter to continue ...");
getchar();
return 0;
}
*/
2. 函数重载的调用准则
/*
编译器调用重载函数的准则
将所有同名函数作为候选者
尝试寻找可行的候选函数
精确匹配实参
通过默认参数能够匹配实参
通过默认类型转换匹配实参
匹配失败
最终寻找到的可行候选函数不唯一,则出现二义性,编译失败。
无法匹配所有候选者,函数未定义,编译失败。
*/
/*
函数重载的注意事项
重载函数在本质上是相互独立的不同函数(静态链编)
重载函数的函数类型是不同的
函数返回值不能作为函数重载的依据
函数重载是由函数名和参数列表决定的。
*/
函数重载是发生在一个类中里面
3. 函数重载遇上函数默认参数
//当函数默认参数遇上函数重载会发生什么
/*
int func(int a, int b, int c = 0)
{
return a * b * c;
}
int func(int a, int b)
{
return a + b;
}
//1 个参数的允许吗
int func(int a)
{
return a + b;
}
int main()
{
int c = 0;
c = func(1, 2); // 存在二义性,调用失败,编译不能通过
printf("c = %d\n", c);
printf("Press enter to continue ...");
getchar();
return 0;
}
*/
4. 函数重载和函数指针结合
/*
函数重载与函数指针
当使用重载函数名对函数指针进行赋值时
根据重载规则挑选与函数指针参数列表一致的候选者
严格匹配候选者的函数类型与函数指针的函数类型
*/
/*
int func(int x) // int(int a)
{
return x;
}
int func(int a, int b)
{
return a + b;
}
int func(const char* s)
{
return strlen(s);
}
typedef int(*PFUNC)(int a); // int(int a)
int main()
{
int c = 0;
PFUNC p = func;
c = p(1);
printf("c = %d\n", c);
printf("Press enter to continue ...");
getchar();
return 0;
}
*/
使用 register 修饰符的注意点,但是使用 register 修饰符有几点限制。
首先, register 变量必须是能被 CPU 所接受的类型。这通常意味着 register 变量必须是一个单个的值,并且长度应该小于或者等于整型的长度。 不过,有些机器的寄存器也能存放浮点数。
其次,因为 register 变量可能不存放在内存中,所以不能用“&” 来获取 register 变量的地址。
由于寄存器的数量有限,而且某些寄存器只能接受特定类型的数据(如指针和浮点数),因此真正起作用的 register 修饰符的数目和类型都依赖于运行程序的机器,而任何多余的register 修饰符都将被编译程序所忽略。
在某些情况下,把变量保存在寄存器中反而会降低程序的运行速度。因为被占用的寄存器不能再用于其它目的;或者变量被使用的次数不够多,不足以装入和存储变量所带来的额外开销。
早期的 C 编译程序不会把变量保存在寄存器中,除非你命令它这样做,这时 register修饰符是 C 语言的一种很有价值的补充。然而, 随着编译程序设计技术的进步,在决定那些变量应该被存到寄存器中时,现在的 C 编译环境能比程序员做出更好的决定。实际上,许多编译程序都会忽略 register 修饰符,因为尽管它完全合法,但它仅仅是暗示而不是命令。
内容总结
以上是互联网集市为您收集整理的03_C++对C函数的扩展全部内容,希望文章能够帮你解决03_C++对C函数的扩展所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。