回調函數
回調函數就是一種利用函數指針進行函數調用的過程. 而那個函數在需要的時候,利用傳遞的位址調用回調函數,這時你可以利用這個機會在回調函數中處理消息或完成一定的操作。
應用程式提供給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++的引用版。