ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Function Pointer及其应用

2021-09-14 17:02:10  阅读:90  来源: 互联网

标签:Function task TStudent int void width 应用 函数指针 Pointer


1、What Is A Function Pointer?

函数指针是将函数赋值给一个变量的方法,即指向函数的指针

示例

我们首先通过一个实例理解函数指针的工作,正常调用函数的代码:

#include<iostream>
void HelloWorld(){
    std::cout<<"Hello World"<<std::endl;
}
int main(){
    HelloWorld();
}

使用函数指针后:

#include<iostream>
void HelloWorld(){
    std::cout<<"Hello World"<<std::endl;
}
int main(){
    void(*function)() = HelloWorld;
    function();
}

运行两个代码发现得到的结果相同

解释

接下来步入正题:

声明一个函数指针:<返回值类型> (*<函数指针名称>)(<参数1的类型>,<参数2的类型>......),例如void Helloworld()函数对应的函数指针可以为:void(*function)(),再例如int add(int a,int b)对应的函数指针可以为:int (*function)(int,int)

当然啦,也可以使用auto关键字:auto function=Helloworld

实际上 void(*function)() = HelloWorld;等价为 void(*function)() = &HelloWorld;,只不过前者用到了隐式转换,这里我要给你们说的是函数指针的实质也是一个地址,指向的是函数在二进制文件中开始的指令所在的地址

实际上我们经常使用typedef关键字对函数指针进行声明和定义,例如 typedef void(*function)()=HelloWorld;

函数指针作为一个实质上的地址当然可以作为参数传入函数:CODE HERE

#include<iostream>
#include<vector>
void PrintValue(int value){
    std::cout<<"Value:"<<value<<std::endl;
}
void ForEach(const std::vector<int>& values,void(*func)(int)){
    for(int value:values)
        func(value);
}
int main(){
    std::vector<int> values={1,5,4,2,3};
    ForEach(values,PrintValue);
}

这里可以扩展一个tip——Lambda(lambda函数是一种初级函数,也是一种匿名函数,用的时候定义,用完即丢弃):

​ 上述代码的另一种表达形式如下:CODE HERE

#include<iostream>
#include<vector>
void ForEach(const std::vector<int>& values,void(*func)(int)){
    for(int value:values)
        func(value);
}
int main(){
    std::vector<int> values={1,5,4,2,3};
    ForEach(values,[](int value){std::cout<<"Value:"<<value<<std::endl;});
}

​ []叫做捕获方式,是定义匿名函数的一种手段,描述如何出入传出参数,后面跟着参数()

这些就是函数指针的基本工作方式和原理,比较简单,但它的应用就显得没那么简单了

2、函数指针的应用一:做一个驱动,提高性能,为程序提供很强的复用性和可扩展性

我们知道计算机的程序是分成一条条指令存储的(例如add,push,pop,cmp等等等),运行程序也是一条条指令运行的。试想一下,用C++写一个InstuctionsParser该如何写:方法显然,对每个指令编写一个函数,根据swich来调用,可是这样直接调用程序性性能以及可扩展性会大打折扣,于是我们可以用表驱动(GOOGLE|BAIDU),另一种方式便是应用函数指针做任务驱动

我们这里是用我课程老师提供的加减法实现作为示例代码,正常实现加减法并调用:

#include <iostream>
using namespace std;
int Add(int a, int b) { return a + b; }
int Minus(int a, int b) { return a - b; }
void main()
{
	char c;
	int op1, op2;
	cin >> c;
	while (c != '#')
	{
		cin >> op1;
		cin >> op2;
		switch (c)
		{
		case '+': cout << Add(op1, op2) << endl;
			break;
		case '-': cout << Minus(op1, op2) << endl;
			break;
		}
		cin >> c;
	}
}
//上述是正常结构化编程的所做的事情,实际上代码复用性和可扩展性非常弱

使用函数指针实现:

//下述使用函数指针FunctionPointer提高代码的复用性和可扩展性
enum OPRAND_TYPE { END = -1, ADD, MINUS };
int Add(int a, int b) { return a + b; }
int Minus(int a, int b) { return a - b; }
struct  Task
{
	int                        op1;
	OPRAND_TYPE   op;
	int                        op2;
};
typedef  int(*FP)(int, int);
FP op[2] = { Add, Minus };
OPRAND_TYPE getTask(Task &task)
{
	char c;
	cin >> c;
	switch (c)
	{
	case '#': task.op = END; break;
	case '+': task.op = ADD;
		cin >> task.op1;
		cin >> task.op2;
		break;
	case '-': task.op = MINUS;
		cin >> task.op1;
		cin >> task.op2;
		break;
	}
	return task.op;
}
void executeTask(const Task task)
{
	op[task.op](task.op1, task.op2);
}
int main()
{
	Task task;
	while (getTask(task) != END)
		executeTask(task);
}

3、函数指针应用二:提供一种泛型的应用

我们写一个冒泡排序如何写呢?

最初的形式:CODE HERE

#include<iostream>
using namespace std;
void MySort(int A[], unsigned int  num)
{
	for (unsigned i = 1; i < num; i++)
	{
		for (unsigned j = 0; j < num - i; j++)
			if (A[j] > A[j + 1])
			{
				int tmp = A[j];
				A[j] = A[j + 1];
				A[j + 1] = tmp;
			}
	}
}
//上述代码显然不能提供一种泛型的解决方案

实际上这个代码只能处理int型的数据冒泡排序,而要提供一种支持所有形式数据排序代码的实现方式,我们可以用到函数指针:CODE HERE

struct TStudent
{
	char name[20];
	int age;
};
void MySort(void *base, unsigned width, unsigned num,
int(*compare)(const void *elem1, const void *elem2)){//这里使用函数指针使用void代表是不明确数据类型的参数,即应用了泛型
	char *A = (char *)base;   //取结构体数组开始的地址
	char *tmp = (char *)malloc(width);//可以自行搜索一下结构体在内存中存储的方式,一个结构体对象占width个字节空间,给结构体对象动态分配一个width大小的空间
	for (unsigned i = 1; i < num; i++) {
		for (unsigned j = 0; j < num - i; j++) {
			if (compare(A + j * width, A + (j + 1)*width) > 0){//if语句的条件判断是作为参数传递过来的一个参数
				memcpy(tmp, A + j * width, width);
				memcpy(A + j * width, A + (j + 1)*width, width);
				memcpy(A + (j + 1)*width, tmp, width);    //这三个语句是做了一次空间上的交换
            }
		}
	}
	free(tmp);
}
int icompare(const void *elem1, const void *elem2)
{
	TStudent *p1 = (TStudent *)elem1;
	TStudent *p2 = (TStudent *)elem2;

	return p1->age - p2->age;
}
int scompare(const void *elem1, const void *elem2)
{
	TStudent *p1 = (TStudent *)elem1;
	TStudent *p2 = (TStudent *)elem2;

	return strcmp(p1->name, p2->name);
}


int main() {
	TStudent student[] = { ("Alan",10),("Blan",18) };
	int num = sizeof(student) / sizeof(student[0]);
	int width = sizeof(student[0]);
	MySort(student, width, num, icompare);
	MySort(student, width, num, scompare);
}

标签:Function,task,TStudent,int,void,width,应用,函数指针,Pointer
来源: https://www.cnblogs.com/YGcatswhite/p/15268395.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有