天天看點

内聯函數/回調函數/仿函數(functor)-------(c++)

  回調函數

  回調函數就是一種利用函數指針進行函數調用的過程. 而那個函數在需要的時候,利用傳遞的位址調用回調函數,這時你可以利用這個機會在回調函數中處理消息或完成一定的操作。

  應用程式提供給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++的引用版。