回调函数
回调函数就是一种利用函数指针进行函数调用的过程. 而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。
应用程序提供给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++的引用版。