1.内置函数
(1)STL(标准模板库):包含了高效的c++程序库,如迭代器
(2)Boost库
2.自定义函数
int sum(int,int); //函数原型,参数名称可以省略而且这样专业
//函数定义
int sum(int num1,int num2)
{
//实现
}
//函数调用
int main()
{
int res = sum(3,4);
return 0;
}
给函数传递参数时,参数值不会直接传递给函数,而是制作参数的副本,存储在栈,再使这个副本可用于函数,而不是使用初始值。
传引用的参数时,在函数内部对参数修改则会影响到实参,因为引用本质上用的是指针,不同的是函数内部使用引用时不用加*号。
数组作为参数传递,实际上传的是数组的指针(首地址)
//由于传递了一个指针又不知道数组的大小,建议一起把大小传进来
void function1(int values[],int len)
{
//内容
}
//调用时参数传递数组名
但是如果不想在方法中修改数组的值可以采用
解决方案:使用const关键字
如void show(const int values[],int len)
或者传递常量指针
如void show(const int*)
void shaow(const int* begin,const int* end)
{
//声明类型一致的ptr
for(const int* ptr=begin;ptr <= end;ptr++){
cout << *ptr << endl;
}
}
//传的时候为
shaow(const values,const values+4);
使用二维数组做参数
#include
using namespace std;
void shoVector(int (*)[2],int);
void show2(int [][2],int);
void showVector(int (*ptr)[2],int len)
{
for(int i=0;i
函数也有地址
使用函数指针可以讲函数作为参数传进来
//函数原型
double sum(double,double);
//函数指针声明
double (*ptrSum)(double,double);
ptrSum=sum;
cout << ptrSum(4,5) << endl;
//或者
cout << (*ptrSum)(4,5) << endl;
注意:
1.该语句声明了一个指针ptrSUm,指向一个函数
2.double *ptrSum(double,double) 不是函数指针,而是声明了一个函数ptrSum,返回double*类型
//对于函数指针作为参数的函数的原型
void prit_result(double (*)(double,double),double,double);
在C++11中增加了auto 还有typedef
如下使用
typedef double (*ptrCal)(double,double);
ptrCal ptrCal1;
inline void func1()
{
//内容
}
//会在mian中将inline的内容替换进来,效率比普通的高,但限于函数代码少经常调用的。类似于#define操作
//在原型或者定义时二选一加inline就行
//前世今生
#define S(num) num*num;
//以后所有使用S(num)的地方被替换为num*num而且没有限定参数的数据类型
int main()
{
int result = S(5);
double result2 = S(3.4);
//缺点
int resl = S(5+10);
//结果为5+10*5+10
//这个问题可以用内敛函数来解决
}
1.引用并非对象,只是为一个已经存在的对象起的别名
2.引用更接近const指针,一旦与某个变量关联起来就将一直效忠于它
3.将引用变量作为参数时函数将使用原始数据,而非副本
4.当数据所占的内存较大时,建议使用引用参数
void swap2(int&,int&);
int main()
{
int num1=2,num2=4;
swap2(num1,num2);
}
void swap2(int& num1,int& num2)
{
int tmp;
tmp=num1;
num1=num2;
num2=tmp;
}
注意这里讨论的都是以返回引用类型的函数的情况
1.千万不要返回局部变量的引用
int& sum() //返回引用类型的函数
{
int num=10;
//注意rNum是在sum()中定义的,为局部变量
//rNum的生命周期只有在sum()中
int& rNum=num;
//函数中的局部变量会被内存回收,给其他变量用,即这块内存已经不是你的了,(不是清零)
return rNum;
}
//另个函数将覆盖先前函数栈上的数据
void test()
{
int x=1;
int y=2;
int z=1024;
}
int main()
{
int& result=sum();
test();//调用其他函数
//会打印出1024
cout << "result = " << result << endl;
return 0;
}
2.函数可以没有返回值,默认返回传入的引用对象本身
int main()
{
int num1=0;
int num2=15;
int& result = sum(num1,num2);
cout << result << endl;
//16 返回的最后一个更新的引用参数,还是老老实实的写返回值最好
}
int& sum(int& num1 , int& num2)
{
num1++;
num2++;
//不能return num1+num2,当以引用类型返回时必须引用参数的其中之一
}
3.返回引用时必须函数参数中包含被返回的引用对象
见上面代码
这个有待考究,没有参数的时候,试验了一下,只要里面返回一个引用对象也是可以的
原文:
1、返回值为引用型(int& )的时候,返回的是地址,因为这里用的是 int& a=mymay.at(); ,所以a和m_data_指的是同一块地址(由寄存器eax传回的5879712)。
2、返回值不是引用型(int)的时候,返回的是一个数值。这个时候就很有意思了,编译器是先将这个数值放入一个内存中(上面例子中,该内存地址为ebp-24h),再把这个地址付给a,此时的a代表的地址是ebp-24h,和m_data_代表的地址不一样(m_data_代表的地址是5879712)。
3、综上两点可以看出,当返回的值不是引用型时,编译器会专门给返回值分配出一块内存的(例子中为ebp-24h)。
int num=10;
int& result= sum(num);
sum(num)=55;
cout << result << endl;
//结果为55
int& sum(int& num)
{
num++;
return num;
}
建议:
1.将返回类型修改为const int&
在声明的时候写或定义时给出,二选一,不能同时
从右向左添加默认值,即默认参数后的参数必须有默认值
void samplt(int=19);
void sample(int num)
{
cout << num << endl;
}
但是注意,不要如下,编译器会分不清所以会报模糊错误 ,因为下面的调用方式都一样的
void eating(string food)
void eating(string& food)
重载本质(重载决议):
编译器在编译时根据参数列表对函数进行重命名
void swap(int n1,int n2) 变 swap_int_int
void swap(float n1, float n2) 变 swap_float_float
也解释了为什么上面那个代码不行,因为重命名完都一样,同样对const
也不敏感
函数模板实际上就是建立一个通用函数
函数定义时不指定具体的数据类型(用虚拟类型代替)
函数被调用时编译器根据实参反推数据类型-类型的参数化
相当于省略了大量写重载函数的过程,写底层框架的时候会大量使用
#include
using namespace std;
//模板头与函数声明/定义永远是不可分割的整体!
//函数声明
template void Swap(T&,T&);
//template也可以,早期写法
template//模板头
void Swap(T& a,T& b)
{
T tmp = a;
a = b;
b = tmp;
}
int main()
{
int n1=3;
int n2=8;
Swap(n1,n2);
cout << n1 << n2 << endl;
return 0;
}