C++中關(guān)于委派(Delegates)的實(shí)現(xiàn)示例
介紹
在 C++ 中通過(guò)一個(gè)全局函數(shù)來(lái)綁定到對(duì)象的成員函數(shù)是很有用的,這個(gè)特性也存在于其他語(yǔ)言中,例如 C#的委派。在 C++ 中相當(dāng)于成員函數(shù)指針,但是 并沒(méi)有提供相應(yīng)的特性。在這篇文章中,我想提出一個(gè)簡(jiǎn)單的 C++ 委派的實(shí)現(xiàn),是用 C++ 成員函數(shù)指針和 C++11 的可變模板(variadic templates),目前這套實(shí)現(xiàn)方法僅支持 GNU C++ 4.7.0,在 Windows 下可使用 MinGW。
背景
在我的方法中獎(jiǎng)提供一個(gè)create_delegate函數(shù),可通過(guò)下面兩種方法來(lái)調(diào)用:
create_delegate(&object, &member_function) create_delegate(&function)
第一種方法創(chuàng)建一個(gè)對(duì)象并提供一個(gè)operator()成員函數(shù),第二個(gè)方法生成一個(gè)函數(shù)指針,兩種方法都兼容 type function<...>.
示例程序
首先我們定義一個(gè)包含多個(gè)方法的類(lèi):
class A
{
int i;
public:
A(int k):i(k) {}
auto get()const ->int { return i;}
auto set(int v)->void { i = v;}
auto inc(int g)->int& { i+=g; return i;}
auto incp(int& g)->int& { g+=i; return g;}
auto f5 (int a1, int a2, int a3, int a4, int a5)const ->int
{
return i+a1+a2+a3+a4+a5;
}
auto set_sum4(int &k, int a1, int a2, int a3, int a4)->void
{
i+=a1+a2+a3+a4;
k = i;
}
auto f8 (int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) const ->int
{
return i+a1+a2+a3+a4+a5+a6+a7+a8;
}
static auto sqr(double x)->double { return x*x; }
};
請(qǐng)注意你并不需要一定使用 C++ 的 auto 函數(shù)語(yǔ)法,你也可以使用傳統(tǒng)的方法,然后我們使用下面方法創(chuàng)建一個(gè)類(lèi):
A a(11);
接下來(lái)我們創(chuàng)建委派:
auto set1 = create_delegate(&a,&A::set); auto inc = create_delegate(&a,&A::inc); std::function<int(int&)> incp = create_delegate(&a,&A::incp); auto af5 = create_delegate(&a,&A::f5); auto set_sum4= create_delegate(&a,&A::set_sum4); auto af8 = create_delegate(&a,&A::f8); auto sqr = create_delegate(&A::sqr); // static function </int(int&)> set1(25); int x = 5; int k = inc(x); k = incp(x); std::cout << "a.get():" << a.get() << std::endl; std::cout << "k: " << k << std::endl; std::cout << "x: " << x << std::endl; std::cout << "af5(1,2,3,4,5): " << af5(1,2,3,4,5) << std::endl; set_sum4(x,1,2,3,20); std::cout << "after set_sum4(x,1,2,3,20)" << std::endl; std::cout << "a.get(): " << a.get() << std::endl; std::cout << "x: " << x << std::endl; std::cout << "af8(1,2,3,4,5,6,7,8): " << af8(1,2,3,4,5,6,7,8) << std::endl; std::cout << "sqr(2.1): " << sqr(2.1) << std::endl;
執(zhí)行上述程序的打印結(jié)果如下:
a.get():30 k: 35 x: 35 af5(1,2,3,4,5): 45 after set_sum4(x,1,2,3,20) a.get(): 56 x: 56 af8(1,2,3,4,5,6,7,8): 92 sqr(2.1): 4.41
關(guān)鍵點(diǎn)
對(duì)于一個(gè)不是 volatile 和 const 的簡(jiǎn)單函數(shù)而言,實(shí)現(xiàn)是非常簡(jiǎn)單的,我們只需要?jiǎng)?chuàng)建一個(gè)類(lèi)保存兩個(gè)指針,一個(gè)是對(duì)象,另外一個(gè)是成員函數(shù):
template <class T, class R, class ... P>
struct _mem_delegate
{
T* m_t;
R (T::*m_f)(P ...);
_mem_delegate(T* t, R (T::*f)(P ...) ):m_t(t),m_f(f) {}
R operator()(P ... p)
{
return (m_t->*m_f)(p ...);
}
};
可變模板 variadic template 允許定義任意個(gè)數(shù)和類(lèi)型參數(shù)的operator()函數(shù),而create_function 實(shí)現(xiàn)只需簡(jiǎn)單返回該類(lèi)的對(duì)象:
template <class T, class R, class ... P>
_mem_delegate<T,R,P ...> create_delegate(T* t, R (T::*f)(P ...))
{
_mem_delegate<T,R,P ...> d(t,f);
return d;
}
實(shí)際中,我們需要另外的三個(gè)實(shí)現(xiàn)用于覆蓋 const、volatile 和 const volatile 三種成員函數(shù),這也是為什么傳統(tǒng)使用 #define 宏很便捷的原因,讓你無(wú)需重寫(xiě)代碼段,下面是完整的實(shí)現(xiàn):
template <class F>
F* create_delegate(F* f)
{
return f;
}
#define _MEM_DELEGATES(_Q,_NAME)\
template <class T, class R, class ... P>\
struct _mem_delegate ## _NAME\
{\
T* m_t;\
R (T::*m_f)(P ...) _Q;\
_mem_delegate ## _NAME(T* t, R (T::*f)(P ...) _Q):m_t(t),m_f(f) {}\
R operator()(P ... p) _Q\
{\
return (m_t->*m_f)(p ...);\
}\
};\
\
template <class T, class R, class ... P>\
_mem_delegate ## _NAME<T,R,P ...> create_delegate(T* t, R (T::*f)(P ...) _Q)\
{\
_mem_delegate ##_NAME<T,R,P ...> d(t,f);\
return d;\
}
_MEM_DELEGATES(,Z)
_MEM_DELEGATES(const,X)
_MEM_DELEGATES(volatile,Y)
_MEM_DELEGATES(const volatile,W)
相關(guān)文章
C++返回值類(lèi)型后置實(shí)現(xiàn)(跟蹤返回值類(lèi)型)
本文主要介紹了C++返回值類(lèi)型后置實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08
C++采用TLS線(xiàn)程局部存儲(chǔ)的用法實(shí)例
這篇文章主要介紹了C++采用TLS線(xiàn)程局部存儲(chǔ)的用法實(shí)例,詳細(xì)講述了TLS索引及線(xiàn)程的操作,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-10-10
C++ 實(shí)現(xiàn)對(duì)象池的具體方法
本文主要介紹了C++ 實(shí)現(xiàn)對(duì)象池的具體方法,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
C++深入分析數(shù)據(jù)在內(nèi)存中的存儲(chǔ)形態(tài)
使用編程語(yǔ)言進(jìn)行編程時(shí),需要用到各種變量來(lái)存儲(chǔ)各種信息。變量保留的是它所存儲(chǔ)的值的內(nèi)存位置。這意味著,當(dāng)您創(chuàng)建一個(gè)變量時(shí),就會(huì)在內(nèi)存中保留一些空間。您可能需要存儲(chǔ)各種數(shù)據(jù)類(lèi)型的信息,操作系統(tǒng)會(huì)根據(jù)變量的數(shù)據(jù)類(lèi)型,來(lái)分配內(nèi)存和決定在保留內(nèi)存中存儲(chǔ)什么2023-01-01
深入理解:Java是類(lèi)型安全的語(yǔ)言,而C++是非類(lèi)型安全的語(yǔ)言
本篇文章是對(duì)Java是類(lèi)型安全的語(yǔ)言,而C++是非類(lèi)型安全的語(yǔ)言進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
Matlab實(shí)現(xiàn)同步子圖視角的方法詳解
這篇文章主要和大家分享三個(gè)可以Matlab中更簡(jiǎn)便實(shí)現(xiàn)同步子圖視角的技巧,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以學(xué)習(xí)一下2022-06-06

