C++笔记(四)【函数】

C++笔记(四)【函数】

文章目录

  • C++笔记(四)【函数】
    • 一、基本知识
      • 1.1 函数分类
      • 1.2 函数三要素
      • 1.3 完整写法
    • 二、参数和按值传递
      • 2.1 基本原理
      • 2.2 数组传参
      • 2.3 二维数组传参
    • 三、函数指针
    • 四、内联(inline)函数
    • 五、参数的引用传递(重点)
      • 5.1 引用回顾
      • 5.2 引用参数
    • 六、函数的返回
      • 6.1 函数返回引用类型
      • 6.2 函数返回变量和返回变量引用的区别
      • 6.3 当作为左值的情况
      • 6.4 小结
    • 七、默认参数
    • 八、函数重载(重点)
    • 8.1 定义
    • 九、函数模板(重点)
      • 9.1 定义

一、基本知识

1.1 函数分类

1.内置函数

(1)STL(标准模板库):包含了高效的c++程序库,如迭代器

C++笔记(四)【函数】_第1张图片

(2)Boost库

2.自定义函数

1.2 函数三要素

  • 返回值类型 (注意不能是数组,可以是其他任何类型,可以讲数组作为结构或对象组成部分返回)
  • 函数名
  • 参数列表

1.3 完整写法

int sum(int,int); //函数原型,参数名称可以省略而且这样专业
//函数定义
int sum(int num1,int num2)
{
	//实现
}
//函数调用
int main()
{
    int res = sum(3,4);
    return 0;
}

二、参数和按值传递

2.1 基本原理

给函数传递参数时,参数值不会直接传递给函数,而是制作参数的副本,存储在栈,再使这个副本可用于函数,而不是使用初始值。

传引用的参数时,在函数内部对参数修改则会影响到实参,因为引用本质上用的是指针,不同的是函数内部使用引用时不用加*号。

2.2 数组传参

数组作为参数传递,实际上传的是数组的指针(首地址)

//由于传递了一个指针又不知道数组的大小,建议一起把大小传进来
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);

2.3 二维数组传参

使用二维数组做参数

#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)函数

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
    //这个问题可以用内敛函数来解决
}

五、参数的引用传递(重点)

5.1 引用回顾

1.引用并非对象,只是为一个已经存在的对象起的别名

2.引用更接近const指针,一旦与某个变量关联起来就将一直效忠于它

3.将引用变量作为参数时函数将使用原始数据,而非副本

4.当数据所占的内存较大时,建议使用引用参数

5.2 引用参数

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;
}

六、函数的返回

6.1 函数返回引用类型

注意这里讨论的都是以返回引用类型的函数的情况

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.返回引用时必须函数参数中包含被返回的引用对象

见上面代码

这个有待考究,没有参数的时候,试验了一下,只要里面返回一个引用对象也是可以的

6.2 函数返回变量和返回变量引用的区别

原文:

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)。

6.3 当作为左值的情况

int num=10;
int& result= sum(num);
sum(num)=55;
cout << result << endl;
//结果为55

int& sum(int& num)
{
    num++;
    return num;
}

建议:

1.将返回类型修改为const int&

6.4 小结

C++笔记(四)【函数】_第2张图片

七、默认参数

在声明的时候写或定义时给出,二选一,不能同时

从右向左添加默认值,即默认参数后的参数必须有默认值

void samplt(int=19);

void sample(int num)
{
    cout << num << endl;
}

八、函数重载(重点)

8.1 定义

  • 指可以有多个同名的函数
  • 函数名相同,参数列表不同

但是注意,不要如下,编译器会分不清所以会报模糊错误 ,因为下面的调用方式都一样的

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也不敏感

九、函数模板(重点)

9.1 定义

函数模板实际上就是建立一个通用函数

函数定义时不指定具体的数据类型(用虚拟类型代替)

函数被调用时编译器根据实参反推数据类型-类型的参数化

相当于省略了大量写重载函数的过程,写底层框架的时候会大量使用

#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;
} 

你可能感兴趣的:(C++笔记,c++,开发语言)