C++函数总结
1、普通函数
普通函数就正常定义,无特殊要说的。
函数的传入参数有传值,引用,指针3中形式。
2、内联函数
为什么要用内联函数:提升执行效率。当一个函数执行的内容简单,又频繁被调用,就写成内联函数,这样执行效率高。
内联函数,内联函数也是函数。就是在编译的时候,程序中,调用函数时,如果是内联函数,编译器会把内联函数复制到调用的地方,执行的时候,就不用跳转到统一的地方去查找了。省了跳转的时间。
3、引用变量:
普通变量,就用按值传递就行,数据量不大。
数组:用指针变量进行传递。
结构体变量:用按引用传递,或者指针的方式传递。
类:按引用传递。
基类的引用可以指向派生类对象。这点很重要,在后面的“类”定义中用的很多。
4、默认参数
默认参数只在函数原型里指定,函数定义时,不能指定。
默认参数只能从最后的变量往前连续设置设置,不能中间有不默认,跳过。
比如: void fun(int a,int b,int c)。可以这样: void fun(int a,int b=1,int c=0);但不可以这样: void fun(int a=1,int b,int c=0)。不能跳过b而设置a.
5、函数重载
函数重载,就是在默认参数的基础上升级。
函数重载就是同一个函数名,但是函数的形参不一样,这个不一样,可以是数量不同,也可以是参数类型不同。
使用的时候,在默认参数不能解决的时候,才用函数重载。
默认参数可以解决形参数数量不同的应用场景。但是解决不了参数类型不同的使用场景。
6、函数模板
函数模板就是在函数重载的基础上再升级。
如果函数参数的个数相同,只是类型不同,要定义的话,使用函数重载, 一个类型就要定义一个函数,太啰唆。
这种场景,用一个模板就能解决。类型用参数表示,也称为参数化类型。
template <typename T> void function(T 变量名,T 变量名){……}。
类似这样定义,把参数的类型就T来表示,使用的时候,你是什么类型,编译的时候,就会把这个T替换成你使用的类型。
7、重载模板
重载模板是重载和模板的杂交。综合了重载的要求:参数特征标不同,模板的要求:类型用参数表示。
这样一结合,就更强大了,使用范围更大,看起来更抽象了。
8、模板的显式具体化
模板好用,但也不是万能的。有些场景可能用起来会有实现。比如不同的类型进行算术运算时就会出问题,比如,模板用T表示类型,如果进行加法运算,T表示整形,那没问题,如果T表示一个结构,就会有问题了,因为没有两个结构体变量相加的运算。这种情况模板是无法解决的。
这种情况有两种解决方案,一种是重载运算符,另一种就是:提供具体化的模板定义。也就是显式具体化。原型的写法就是:
tempate<> function<结构类型名>(结构体类型名 a,结构体类型名 b);
简单说,就是模板函数的一个特例。
9、延伸知识:
1、 隐式实例化,显示实例化
模板在编译的时候,编译器根据调用的参数类型,生成实例,这个叫隐式实例化。一般定义模板函数,使用时,都是编译器这么生成实例的。
但是,也可以人为指定,不让编译器在调用的时候才生成实例,可以强制编译器看到这个定义的时候就生成实例,这个就是显式实例化。
显示实例化的定义:(template少一个<>)。
template function<int> (int a,int b);
2、类型推测
由于使用模板函数,可能有多个参数类型,这就导致 变量a+变量b之后的结果的类型是变量a的类型还是变量b的类型,针对这种问题,就新增了关键字:decltype。定义时,将这个关键字放在结果变量前,表示根据操作数的类型自动匹配结果变量的类型。
另外,模板函数的返回值类型上也会存在这种问题,这种情况不能用decltype关键字定义,国为这个时间,函数的参数还没有定义,不能推测。
针对这种情况,新增语法:后置返回类型。写法:
auto function(int x,inty)->double{……}。合并decltype使用就是:
template <typename T1, typename T2> auto function(T1 x,T2 y)->decltype(x+y) {……}
auo只是用来占位,表示这里有个返回类型,而具是什么类型,就要看->decltype() 的结果。
10、总结:
关于函数:普通函数->模板函数->显示具体化函数。
重载:普通函数,模板函数,显示具体化函数都可以重载。
模板的显示具体化和显示实例化定义不能同时出现在一个文件里。(其实他俩,经过编译器生成之后 ,是同一个函数,所以不能同时出现,否则是重复定义,有歧义,所以不允许同时出现)
编译器匹配函数的优先顺序:普通函数->模板具体化函数->模板函数。当然,涉及到重载,更复杂,但大致方向就是这个。