程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> vc教程 >> C++實現.NET風格的委托

C++實現.NET風格的委托

編輯:vc教程

引言

在.NET中,委托被用來實現事件處理。它允許一個類(方法)先注冊一個事件,然後當此事件被引發時此注冊的方法就會被調用。在非.Net環境的C++中,這並不是一件容易的事,尤其是類的非靜態成員函數,要做為回調函數就更困難了。本文的目標就是給出一種解決方案, 使類的靜態成員函數,非靜態成員函數,還有類非成員函數都能像回調函數一樣使用。這個實現非常重視類型安全,為了保持類型安全我們省去了某些特性的實現。

什麼是委托?

.NET框架中對委托的定義如下:

"委托是一個可以保持對某個方法引用的類。不同於其它類,委托類有自己的簽名(返回值,參數類型,個數),並且只能引用與其簽名匹配的方法。委托其實可以看成一個類型安全的函數指針或回調函數。

一個提供了委托的類允許其它函數或類在此委托上注冊事件處理函數。然後當這個類的委托被執行時,就會遍歷其處理函數列表,逐個調用,並傳入傳給委托的信息。而提供委托的那個類不需要知道委托注冊了多少處理函數,委托自己會處理這一切。

正文

函數對象(functor)概述

我們用函數對象(functor, function object)來實現C++中的委托。這允許一個非靜態成員函數能在特定對象的環境中被調用。我們用模板技術來保證任何類類型都能在其上使用。一個基本的函數對象(functor)定義如下:

template<class T>
class Functor
{
public:
// Constructor takes the values and stores them
Functor(T *pObj, int (T::*pFunc)(int))
{
m_pObject = pObj;
m_pFunction = pFunc;
}
// Invokes the stored function
intoperator ()(int p)
{
return (m_pObject->*m_pFunction)(p);
}
private:
T *m_pObject; // Pointer to the object
int (T::*m_pFunction)(int); // Pointer to the function
};
  這個函數對象(functor)使用的函數格式為:返回類型為int,帶一個類型為int的參數。操作符operator ()是函數對象的關鍵。它使一個函數對象(functor)使用起來和函數調用一樣。它的工作就是每次執行時調用保存在類內部的函數指針。以下代碼展示了如何使用這個函數對象(functor):
class MyClass
{
public:
int Square(int p) { return p * p; };
};
void some_function()
{
// Create a class to call in the context of
MyClass theClass;
// Create and initialise the functor object
Functor<MyClass> myFunc(&theClass, MyClass::Square);
// Call the functor using the overloaded () operator
int result = myFunc(5);
// result will hold the value 25
}
  由於重載了operator ()運算符,調用函數對象(functor)幾乎就和調用該函數本身一樣方便。這裡說“幾乎”是因為指向實際對象的指針並沒有被顯示使用-它被存放在函數對象(functor)內部使用。

的確,這很不錯,但是我們為什麼要使用函數對象(functor),而不是函數本身呢?很好的問題,當你知道你要調用的函數的簽名(返回值和參數)而不關心其是否是類的成員函數,是哪個類的成員函數時,函數對象就非常的有用(譯注:將這一信息局部化在對象內部,從而以統一的方式來調用所有具有相同簽名的函數)看以下代碼,我將它們劃分成幾項以便理解:

首先,是一個用純虛基類來表示的一個以一個int為參數,返回值為int的函數對象。它只有一個函數,虛擬的operator()操作符,這樣,我們就可以在不知道某函數對象實例的實際對象類型的情況下調用函數對象(functor)了.

// Abstract base class
class Functor
{
public:
// Invoke the functor (no implementation here as it must be overridden)
virtualintoperator()(int) = 0;
};
  下面就是一個可以被實例化為任何類類型的模板類,假設它也有一個以一個int為參數,返回為int的函數。它是從Functor派生來的,所以一個指向特定函數對象的指針可以傳給任何一個需要其基類對象(Functor)指針的地方,所以此函數對象可以不管其真正的對象類型而被調用。除了基類和類名,這個類與之前給出的類是完全一樣的:
// Template functor
template<class T>
class TemplateFunctor : public Functor
{
public:
// Constructor takes the values and stores them
TemplateFunctor(T *pObj, int (T::*pFunc)(int))
{
m_pObject = pObj;
m_pFunction = pFunc;
}
// Invokes the stored function (overrides Functor::operator ())
intoperator ()(int p)
{
return (m_pObject->*m_pFunction)(p);
}
private:
T *m_pObject; // Pointer to the object
int (T::*m_pFunction)(int); // Pointer to the function
};
  下面是一個以函數對象指針和該函數的參數為參數的簡單函數,用來調用該函數對象。注意這裡以基類Functor指針而不是派生模板類指針為參數。這是必需的, 因為每一個不同的模板參數產生的模板類都是不同的類型,直接用此模板類為參數就不能支持多種類型了。

int OperateOnFunctor(int i, Functor *pFunc)
{
if(pFunc)
return (*pFunc)(i);
else
return0;
}
  這是一個簡單的類,它包含了一個符合函數對象要求的函數-以一個int為參數並返回一個int。注意此函數還用到了一個該類的數據成員,這說明這個回調函數實際應該是在實例對象的環境下被執行的, 所以引用同一類不同對象的函數對象會產生不同的結果:

class ClassA
{
public:
ClassA(int i) { m_Value = i; }
int FuncA(int i)
{
return (m_Value - i);
}
int m_Value;
};

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved