函数模板
由于本人也是一位新的C++Coder,出于对C/C++的兴趣爱好,所以学习,这些也都是相关的学习笔记类的.如有写的不好或者不对的地方.求谅解.
为什么要引入引用的概念:
C语言函数的参数传递
按值传递,按值传递如果传递很大数据项,复制数据将导致较长的执行时间,所有在C语言中很多时候我们都是使用指针传参
C++
按值传递
按引用传递,避免复制大量数据的开销,提高性能
当然C++中肯定也是可以使用指针进行传参的
引用特性
1:引用是别名,在声明时必须初始化,在实际代码中主要用作函数的形式参数
2: 引用作为目标的别名(小名)而使用,对引用的改动实际上是对目标的改动
3:为了建立引用,先写上目标的类型,再加上引用运算符”&”,然后是引用的名字
4:对引用的修改其实就是对原来变量的值的修改
5:引用的地址与引用变量的地址指向的是同一个地址
如:
int& a;
引用是
const int *p = &a的伪代码(常量指针,指向的地址是常亮,不允许进行改变的)
例子:
int intOne;
int& rInt = intOne;
intOne = 5;
cout <<"intOne :"<
引用操作:
&只有在声明引用时候是引用操作符,其他时候都是地址操作符号
引用和变量指向同一个存储单元
引用一旦初始化,它就维系在一定的目标上,再也不会分开
int val = 0;
int& rVal = val;
cout <<&(val) <
引用和指针的差别:
1:指针是个变量,可以把它再赋值成别处的地址
2:建立引用时必须进行初始化并且绝对保证不会再关联其他不同的变量
3:由于指针也是变量,所有可以有指针变量的引用
int *a = NULL;
int *&rpa = a;
int b = 8;
rpa = &b;
4:void引用是不合法的 ------->void &a = 3;
5:不能建立引用的数组
绝对禁止:int & a[10] = b;
6:没有引用的指针和引用的引用
7:有空指针无空引用
引用的参数传递:
传递引用给函数与传递指针的效果是一样的
使用引用作为参数比使用指针作为参数有更清晰的语法
void swap(int&x,int&y);
void swap(int&x,int&y){
int temp;
temp = x;
x = y;
y = temp;
}
使用引用作为参数和返回值给函数的意义:
函数只能返回一个值,如果程序需要从函数返回两个数值怎么办
解决这一个问题的办法之一就是引用给函数传递两个参数,然后由往目标中填入争取的数值
函数返回值时,要生成一个值副本,而用引用返回值时候,不生成值的副本,所以提高了效率
int result = 0; //注意要在返回引用之外;
int& func(int r){ //返回引用
result = r*r;
return result;
}
如果返回不在作用域范围内的变量或对象的引用的时候,那么这个时候就是有很大问题的,这是返回一个局部作用域指针的性质是一样的(局部变量在调用完毕之后在栈中内存会被回收掉,这就导致其指向的空间值具有不确定性的数值)
/*
* ===========================================================================
*
* Filename: reference.cpp
* Description:
* Version: 1.0
* Created: 2017年05月23日 23时18分32秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#include
using namespace::std;
void swap(int &swap_num_1,int& swap_num_2);
int & return_result(int &num);
int main(int argc,char * argv[]){
int intOne;
int &intOneReference = intOne;
intOne = 10;
cout << intOne << endl;
cout << intOneReference <//对引用的修改其实就是对引用的变量的修改
intOneReference = 15;
cout << intOne << endl;
cout << intOneReference <cout << "=================="<cout << &intOneReference <cout << &intOne << endl;
int num1 = 10;
int num2 = 20;
swap(num1,num2);
cout << num1 << endl;
cout << num2 << endl;
int a = 10;
int &num = a;
num = return_result(num);
cout <return 0;
}
void swap(int &swap_num_1,int& swap_num_2){
int num;
num = swap_num_1;
swap_num_1 = swap_num_2;
swap_num_2 = num;
}
int& return_result(int &num){
num = num * num;
return num;
}
内联函数
函数:
函数能够从输入数据或参数获得信息
输入数据流----->函数---->返回值
函数调用需要建立栈内存环境,进行参数传递,并产生程序的执行转移,这些工作都需要一些时间开销。有些函数使用频率高,但代码却很短;
C++提供了inline函数,减少函数调用的成本
编译器看到inline后,为该函数 创建一段代码,以便在后面每次碰到该函数的调用都用一段代码来代替
内联函数的声明:
内联函数必须在调用之前声明或定义;
例子:
inline boolean isnumber(char);
char c;
while((c=cin.get())!='\n'){
if(isnumber(c))
cout<<"you enter a digit \n";
else
cout<<"you enter a non-digit \n";
}
inline booelan isnumber(char c){
return (c>='0'&&c<='9')?true:false;
}
内联函数的函数体限制
1:内联函数中,不能有复杂的结构控制语句,如switch和while。如果内联函数有这些语句,编译器则视其为普通函数
2:递归函数不能做内联函数
3:将大多数inline函数限制在小型,被频繁调用的函数上
4:内联函数只适合于只有1到5行的小函数,对于比较长的函数,函数调用和返回的开销相对来说都微不足道,所有也没有必要用内联动函数
内联函数和宏定义:
宏定义可以代替小函数定义,但是有缺陷
宏只是告诉编译器简单的替代代码。不检查参数类型
往往造成语句的实际结果不能代表程序员的意图
通过一个内联函数可以得到所有宏的替换功能和所有可遇见的状态及常规函数的就类型检查
inline int Max(int a,int b)【
return a>b?a:b
}
默认参数的函数:
默认参数的函数
给一个函数默认参数的值
调用函数的时候可以不指定全部的参数
为可以不指定的参数提供默认值:
int add(int x = 5,int y = 6,int z = 3);
int main(){
add(); //所有这三个参数都采用默认值
add(1,5); //第三个参数采用默认值
add(1,2,3); //不采用默认值
}
默认参数的顺序规定:
如果一个函数中的有多个默认参数,则形参分布中,默认参数应从右往左逐渐定义,当调用函数时候,只能向左匹配参数,例如:
void func(int a = 1,int b,int c = 3,int d = 4); //error
void func(int a,int b = 2,int c = 3,int d = 4);//ok
对于第二个函数声明,其调用的方法规定为:
func(10,15,20,30);//调用的时候给出实际的参数
func();//error
func(12,12);参数c,d默认
func(2,15,,20);//只能从右往左便开始匹配
如果是有默认参数的情况下,内部的参数是可以不用写那么全的
如 foo(int a = 30,int b = 40,int c = 50);
那么此时调用的时候可以
foo(30);
foo(30,40);
foo(30,40,50);
函数重载:
函数重载:
定义:两个或者两个以上的函数,取相同的函数名字,但是形参数的个数或者类型不同,编译器根据实参和形参数的类型及个数的最佳匹配,自动确定调用哪一个函数,这就是函数的重载;
重载的重要性:
在C语言中每个函数都必须要有唯一的名字
int abs(int);
long labs(long);
double dabs(double);
这每个函数所做的事情都是一样的,相对比较冗余;
C++中:
int abs(int);
long abs(long);
double abs(double);
C++用一种命名技术可以准确判断使用哪一个函数;
函数重载的顺序:
寻找一个严格的匹配,如果找到了那就用哪一个函数
通过内部转换寻求一个匹配,只要找到了,就用那个函数
通过用户定义的转换寻求一个匹配,若能查出有唯一的一组转换,就用那个函数
FILE
LINE
func
默认参数和函数重载:
默认参数可将一系列简单的重载函数合成一个
void point(int ,int){
}
void point(int a){
return point(a,4);
}
void point(){
return point(3,4);
}
可以用默认参数的函数来替代:
void point(int=3,int=4);
如果一组重载函数都允许相同实参个数的调用,将会引起调用的二异性:
在C语言头文件中的extern “C”
常见的C语言头文件格式:
#ifndef __FUNC__
#define __FUNC__
#ifdef __cplusplus
extern "C"{
#endif
void func();
int foo(int a,int b);
#ifdef __cplusplus
}
#endif
#endif
函数模板(template):
泛型编程:独立于任何特定类型的方式编码
模板是泛型编程的基础
模板使程序员能够快速建立具有类安全的类库集合和函数集合
它的实现方便了大规模的软件开发
现有的框架Framework大都使用模板
类模板和函数模板
STL是标准的模板库
函数模板的定义:
template<类型形式参数表> 返回类型 FunctionName(形式参数表)
//函数定义体
}
例子:求绝对值的模板:
#include
using namespace::std;
template
T abs(T x){
return x<0 ? -x : x;
}
int main(){
int n = 5;
double d = -5.5;
cout <(b)?a:b)
template
T max(T a,T b){
return a>b ?a :b;
}