回调函数
回调函数就是一种利用函数指针进行函数调用的过程. 而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。
应用程序提供给Windows系统DLL或其它DLL调用的函数,一般用于截获消息、获取系统信息或处理
异步事件。应用程序把回调函数的地址指针告诉DLL,而DLL在适当的时候会调用该函数。(一般为标
准WindowsAPI的调用方式---__stdcall)
注意:
I、 不能显式调用的函数,通过将回调函数的地址传给调用者从而实现调用。
II、 必须遵守事先规定好参数格式和传递方式,
III、函数(DLL编制者)和客户程序也必须遵守相同的调用约定。
V、 一般只有DLL中使用回调函数
关于定义函数指针的声明与函数声明。
void f();// 函数原型
void (*) ();//声明一个返回Void类型无参数函数指针。
unsigned psize = sizeof (void (*) ()); // 获得函数指针的大小
typedef void (*pfv) ();// 为函数指针声明类型定义
- #include<iostream.h>
- void fun(int i,int j)
- {
- i=10;
- j=20;
- cout<<i<<endl<<j<<endl;
- }
- void callfun(void(*p)(int,int),int n,int a,int b)
- {
- if(n>10)
- p(a,b);
- }
- void main()
- {
- void (*p) (int ,int ); //定义一个函数指针变量P
- p=fun;
- callfun(p,100,0,0);
- }
附关于C#实现回调函数(借用委托)
- using System;
- using System.Runtime.InteropServices;
- public delegate bool CallBack(int hwnd, int lParam);
- public class EnumReportApp {
- [DllImport("user32")]
- public static extern int EnumWindows(CallBack x, int y);
- public static void Main()
- {
- CallBack myCallBack = new CallBack(EnumReportApp.Report);
- EnumWindows(myCallBack, 0);
- }
- public static bool Report(int hwnd, int lParam) {
- Console.Write("Window handle is ");
- Console.WriteLine(hwnd);
- return true;
- }
- }
附: API函数的参数采用指向回调函数的指针,其名称中通常会有 lp(长指针)前缀与 Func 后缀的组合。
如: BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)
内联函数
内联函数是代码被插入到调用者代码串处的函数。如同 #define 宏,内联函数通过避免被调用的
开销来提高执行效率,尤其是它能够通过调用(“过程化集成”)被编译器优化。
在函数声明或定义中函数返回类型前加上关键字inline即把min()指定为内联。
优点:
内联能提高函数的执行效率,省去了函数调用的开销,从而提高函数的
执行效率
缺点:
如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收
获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大
- 附:内联函数与#define 宏比较
- // 返回 i 的绝对值的宏
- #define unsafe(i) /
- ( (i) >= 0 ? (i) : -(i) )
- // 返回 i 的绝对值的内联函数
- inline
- int safe(int i)
- {
- return i >= 0 ? i : -i;
- }
- int f();
- void userCode(int x)
- {
- int ans;
- ans = unsafe(x++); // 错误!x 被增加两次
- ans = unsafe(f()); // 危险!f()被调用两次
- ans = safe(x++); // 正确! x 被增加一次
- ans = safe(f()); // 正确! f() 被调用一次
- }
- 和宏不同的,还有内联函数的参数类型被检查,并且被正确地进行必要的转换。
仿函数(functor)
仿函数是通过重载()运算符模拟函数形为的类。
明确两点:
I、 仿函数不是函数,它是个类;
II、仿函数重载了()运算符,来达到模拟函数调用效果;
- 实例:
- #include <iostream>
- using namespace std;
- const int CMP_LES = -1;
- const int CMP_EQU = 0;
- const int CMP_BIG = 1;
- class Comparer
- {
- public:
- Comparer(int cmpType)
- {
- m_cmpType = cmpType;
- }
- bool operator ()(int num1, int num2) const
- {
- bool res;
- switch(m_cmpType)
- {
- case CMP_LES:
- res = num1 < num2;
- break;
- case CMP_EQU:
- res = num1 == num2;
- break;
- case CMP_BIG:
- res = num1 > num2;
- break;
- default:
- res = false;
- break;
- }
- return res;
- }
- private:
- int m_cmpType;
- };
- void Swap(int &num1, int &num2)
- {
- int temp = num1;
- num1 = num2;
- num2 = temp;
- }
- void SortArray(int array[], int size, const Comparer &cmp)
- {
- for (int i = 0; i < size - 1; ++i)
- {
- int indx = i;
- for (int j = i + 1; j < size; ++j)
- {
- if (cmp(array[indx], array[j]))
- {
- indx = j;
- }
- }
- if (indx != i)
- {
- Swap(array[i], array[indx]);
- }
- }
- }
- void ListArray(int array[], int size)
- {
- for (int i = 0; i < size; ++i)
- {
- cout << array[i] << " ";
- }
- }
- #define ARY_SIZE 10
- int main()
- {
- int array[ARY_SIZE] = {10, 12, 9, 31, 93, 34, 98, 9, 1, 20};
- cout << "The initial array is : ";
- ListArray(array, ARY_SIZE);
- cout << endl;
- SortArray(array, ARY_SIZE, Comparer(CMP_BIG));
- cout << "The ascending sorted array is :";
- ListArray(array, ARY_SIZE);
- cout << endl;
- SortArray(array, ARY_SIZE, Comparer(CMP_LES));
- cout << "The descending sorted array is : ";
- ListArray(array, ARY_SIZE);
- cout << endl;
- return 0;
- }
- 运行结果:
- The initial array is : 10 12 9 31 93 34 98 9 1 20
- The ascending sorted array is :1 9 9 10 12 20 31 34 93 98
- The descending sorted array is : 98 93 34 31 20 12 10 9 9 1
- 程序中定义了一个仿函数Comparer,它重重载了()运算符:
- Comparer::bool operator ()(int num1, int num2) const;
- 这里温习一下运算符重载的方式:
- ret_type operator opt(array_list);
- 其中,ret_type为运算符重载后返回值的类型,operator为c++运算符重载专用关健字,opt为所要重载的运算符,如+, -, *, /, [], ()...
- 于是我们可以解读Comparer::bool operator ()(int num1, int num2) const的意义:
- bool限定了()的返回值为布尔类型,(int num1, int num2)指定了运算符()的参数形式,const使得应该运算符可被它的const对象调用。()运算符中根据m_cmpType值返回不同方式下两整数的比较值。
- 函数void SortArray(int array[], int size, const Comparer &cmp)用于给数组排序。其中,array[]指定所要排序的数组对象,size限定数组元素个数,cmp为Comparer对象的引用,用作对元素的比较使用,前面使用const修饰是向函数调用都声明,在函数内不会有修改该对象任何数据的形为。注意SortArray中的代码:
- if (cmp(array[indx], array[j]))
- {
- indx = j;
- }
- 其中,cmp为Comparer类的一个对象,但这里的用法好像它是某个函数的样子。这就是仿函数的真谛。
- 别外,void Swap(int &num1, int &num2)完成交换num1与num2值的功能。int &num1表示函数参数使用的引用,用久了c的朋友也许更习惯了void Swap(int *num1, int *num2),但在c++中这个习惯要改了,引用和指针一样高效,但引用要比指针更直观。下面是指针版的Swap函数:
- void Swap(int *num1, int *num2)
- {
- int temp = *num1;
- *num1 = *num2;
- *num2 = temp;
- }
- 实现的功能与程序中使用的一模一样,替换掉程序照样正常工作。仔细比较引用版与指针版的Swap()函数,我相信大多数人会爱上C++的引用版。