函数指针
函数指针的目的与意义:抽象数据与抽象代码
函数的地址:函数入口位置,将该数值作为数据保存起来,就可以通过特殊手段调用该函数
typedef void* ADT;
typedef const void * CADT;
- 函数指针的定义
数据类型 (as_string)(ADT object);
as_string作为变量可以指向任何带有一个ADT类型参数的返回值char类型的函数
函数指针变量可以像普通变量一样赋值
函数指针数据对象名称=函数名称
char* DoTransformObjectIntoString(ADT object)
{return PtTransformIntoString((PPoint)object);}
as_string = DoTransformObjectIntoString; - 函数指针的使用
通过函数指针调用函数
通过指针被赋值后,即指向实际函数的入口地址
通过函数指针可以直接调用它所指向的函数
调用示例:
char* returned_value;
PPOINT pt=PtCreate(10, 20);
as_string = DoTransformObjectIntoString;
returned_value=as_string((ADT)pt);
需要区分函数指针调用和函数指针直接调用,使用下述格式调用函数指针指向的函数:
returned_value = (*as_string)((ADT)pt);
设计程序,随机生成8个10~99之间的整数,调用stdlib库的qsort函数对其进行排序
qsort函数原型
void qsort(void base, unsigned int number_of_elements, unsigned int size_of_elements, int (compare)(const void, const void ));
调用时需按照下述格式实现自己的比较函数
int(compre)(const void,const void);
比较函数示例:
int MyCompareFunc(const voide1, const void* e2);
比较函数必须返回正负值(一般为正负1或0),规则按照题目要求自定义
示例:
//main.cpp
#include <iostream>
#include <cstdlib>
using namespace std;
#include "arrmanip.h"
#define NUMBER_OF_ELEMENTS 8
int DoCompareObject(const void* e1, const void* e2);
int main()
{
int a[NUMBER_OF_ELEMENTS];
GenerateIntegers(a, NUMBER_OF_ELEMENTS);
cout<<"Array generated at random as follows:"<<endl;
PrintIntegers(a, NUMBER_OF_ELEMENTS);
qsort(a, NUMBER_OF_ELEMENTS, sizeof(int), DoCompareObject);
cout<<"After sorted:"<<endl;
PrintIntegers(a, NUMBER_OF_ELEMENTS);
return 0;
}
int DoCompareObject(const void*e1, const void*e2)
{
return CompareInteger(*(const int*)e1, *(const int*)e2);
}
//arrmanip.h
void GenerateIntegers(int a[], unsigned int n);
int CompareInteger(int x, int y);
void PrintIntegers(int a[], unsigned int n);
//arrmanip.cpp
#include <iostream>
using namespace std;
#include "random.h"
#include "arrmanip.h"
static const unsigned int lower_bound=10;
static const unsigned int upper_bound=99;
void GenerateIntegers(int a[], unsigned int n)
{
unsigned int i;
Randomize();
for(i=0;i<n;i++)
{
a[i]=GenerateRandomNumber(lower_bound, upper_bound);
}
}
函数指针的赋值
同类型函数指针可以赋值,不同类型则不能赋值
如何确定函数指针类型是否相同:函数参数与返回值不完全相同
函数指针类型:用于区分不同类型的函数指针
typedef int (COMPARE_OBJECT)(const voide1, const voide2);
前面添加typedef 关键字,保证COMPARE_OBJECT为函数指针类型,而不是函数指针变量
可以像普通类型一样使用函数指针类型定义变量:
COMPARE_OBJECT compare=DoCompareObject;
qsort函数的简明写法
void qsort(voidbase, unsigned int number_of_elements,unsigned int size_of_elements,COMPARE_OBJECT compare);
- 抽象列表
1、回调函数:允许通过函数指针调用未来才会实现的代码
回调函数:依赖后续设计才能确定的被调函数
示例:DoCompareObject
2、回调函数参数
回调函数与主调函数的信息交互:附加信息
3、数据对象的存储与删除
删除链表结点时,其中的目标数据对象是否需要删除?
如果链表结点存储的是指针,就需要删除,否则不需要
设计抽象链表时候,并不了解结点实际存储的数据是否为指针,因而无法确定结点数据操作逻辑 - 回调函数
编写函数,遍历链表,结点数据的具体操作方法目前未知,由未来的回调函数提供
typedef void (*MANIPULATE_OBJECT)(ADT e);
void LlTraverse(PLIST list, MANIPULATE_OBJECT manipulate)
{
PNODE t=list->head;
if(!list)
{ cout<<"LlTraverse:Parameter illegal."<<endl;
exit(1);
}
while(t)
{
if(manipulate) //通过函数指针调用实际函数操纵目标数据对象
(*manipulate)(t->data);
t=t->next;
}
}
//回调函数参数
typedef void (*MANIPULATE_OBJECT)(ADT e, ADT tag);
void LlTraverse(PLIST list, MANIPULATE_OBJECT manipulate, ADT tag)
{
PNODE t=list->head;
if(!list)
{ cout<<"LlTraverse:Parameter illegal."<<endl;
exit(1);
}
while(t)
{
if(manipulate) //通过函数指针调用实际函数操纵目标数据对象
(*manipulate)(t->data, tag);
t=t->next;
}
}
//示例
//点数据到字符串的转换函数,最终程序员任意定义
//参数format表示点数据对象的转换格式
//其中只能表示两个格式%d,其它内容任意
//例如格式"[%d, %d]","(%d, %d)"等
char* PtTransformIntoString(const char* format, PPoint point)
{
char buf[BUFSIZ];
if(point)
{
sprintf(buf, format, point->x, point->y);
return DuplicateString(buf);
}
else
return "NULL";
}
//回调函数DoPrintObject
void DoPrintObject(ADT e, ADT tag)
{
printf(PtTransformIntoString((const char*)tag, ((PPOINT)e));
printf("->");
}
//回调函数参数的意义
//调用遍历函数时将点数据的输出格式传递给遍历函数,再由遍历函数传递给回调
LlTraverse(list, DoPrintObject, "(%d, %d)");