将类的成员函数作为回调函数(外一篇:友元函数)
轉(zhuǎn)自:http://blog.csdn.net/xylary/article/details/1548596
提出問(wèn)題:?
回調(diào)函數(shù)是基于C編程的Windows SDK的技術(shù),不是針對(duì)C++的,程序員可以將一個(gè)C函數(shù)直接作為回調(diào)函數(shù),但是如果試圖直接使用C++的成員函數(shù)作為回調(diào)函數(shù)將發(fā)生錯(cuò)誤,甚至編譯就不能通過(guò)。
分析原因:
普通的C++成員函數(shù)都隱含了一個(gè)傳遞函數(shù)作為參數(shù),亦即“this”指針,C++通過(guò)傳遞一個(gè)指向自身的指針給其成員函數(shù)從而實(shí)現(xiàn)程序函數(shù)可以訪問(wèn)C++的數(shù)據(jù)成員。這也可以理解為什么C++類(lèi)的多個(gè)實(shí)例可以共享成員函數(shù)但是確有不同的數(shù)據(jù)成員。由于this指針的作用,使得將一個(gè)CALLBACK型的成員函數(shù)作為回調(diào)函數(shù)安裝時(shí)就會(huì)因?yàn)殡[含的this指針使得函數(shù)參數(shù)個(gè)數(shù)不匹配,從而導(dǎo)致回調(diào)函數(shù)安裝失敗
解決方案:
一,不使用成員函數(shù),直接使用普通C函數(shù),為了實(shí)現(xiàn)在C函數(shù)中可以訪問(wèn)類(lèi)的成員變量,可以使用友元操作符(friend),在C++中將該C函數(shù)說(shuō)明為類(lèi)的友元即可。這種處理機(jī)制與普通的C編程中使用回調(diào)函數(shù)一樣。
二,使用靜態(tài)成員函數(shù),靜態(tài)成員函數(shù)不使用this指針作為隱含參數(shù),這樣就可以作為回調(diào)函數(shù)了。靜態(tài)成員函數(shù)具有兩大特點(diǎn):其一,可以在沒(méi)有類(lèi)實(shí)例的情況下使用;其二,只能訪問(wèn)靜態(tài)成員變量和靜態(tài)成員函數(shù),不能訪問(wèn)非靜態(tài)成員變量和非靜態(tài)成員函數(shù)。由于在C++中使用類(lèi)成員函數(shù)作為回調(diào)函數(shù)的目的就是為了訪問(wèn)所有的成員變量和成員函數(shù),如果作不到這一點(diǎn)將不具有實(shí)際意義。我們通過(guò)使用靜態(tài)成員函數(shù)對(duì)非靜態(tài)成員函數(shù)包裝的辦法來(lái)解決問(wèn)題。類(lèi)實(shí)例可以通過(guò)附加參數(shù)或全局變量的方式的方式傳遞到靜態(tài)成員函數(shù)中。分別舉例如下:
1,參數(shù)傳遞的方式
?? #include <iostream.h>???
?? class TClassA
?? {
?? public:
????? void Display(const char* text) { cout << text << endl; };
????? static void Wrapper_To_Call_Display(void* pt2Object, char* text);
??????// more....
?? };
???// 靜態(tài)包裝函數(shù),能夠調(diào)用成員函數(shù)Display(),本身做為回調(diào)函數(shù)來(lái)使用
?? void TClassA::Wrapper_To_Call_Display(void* pt2Object, char* string)
?? {
?????? // 顯式類(lèi)型轉(zhuǎn)換
?????? TClassA* mySelf = (TClassA*) pt2Object;
?????? // 調(diào)用普通成員函數(shù)
?????? mySelf->Display(string);
?? }
???// 回調(diào)函數(shù)的宿主,在這里回調(diào)用函數(shù)被使用
?? void DoItA(void* pt2Object, void (*pt2Function)(void* pt2Object, char* text))
?? {
??????// 使用回調(diào)函數(shù)
????? pt2Function(pt2Object, "hi, i'm calling back using a argument ;-)");??
?? }
?? // 執(zhí)行示例
?? void Callback_Using_Argument()
?? {
????? TClassA objA;
????? DoItA((void*) &objA, TClassA::Wrapper_To_Call_Display);
?? }
2,全局變量的方式
?? #include <iostream.h>???
?? void* pt2Object;??????? // 全局變量,可以指向任意對(duì)象
?? class TClassB
?? {
?? public:
????? void Display(const char* text) { cout << text << endl; };
????? static void Wrapper_To_Call_Display(char* text);
?? };
?? // 靜態(tài)的包裝函數(shù)
?? void TClassB::Wrapper_To_Call_Display(char* string)
?? {
???????//需要保證全局變量值的正確性
?????? TClassB* mySelf = (TClassB*) pt2Object;
?????? mySelf->Display(string);
?? }
?? // 回調(diào)用函數(shù)的宿主,在這里回調(diào)用函數(shù)被使用
?? void DoItB(void (*pt2Function)(char* text))
?? {
???
????? pt2Function("hi, i'm calling back using a global ;-)");?? // make callback
?? }
?? // 執(zhí)行示例
?? void Callback_Using_Global()
?? {
????? TClassB objB;??
????? pt2Object = (void*) &objB;
????? DoItB(TClassB::Wrapper_To_Call_Display);
?? }
注意:通過(guò)上面兩種方法的比較可以看出,第2種方法中靜態(tài)包裝函數(shù)可以和普通成員函數(shù)保持簽名一致,當(dāng)回調(diào)函數(shù)的宿主接口不能改變時(shí),這種方法特別有用。但因?yàn)槭褂昧巳肿兞?#xff0c;也不是一個(gè)好的設(shè)計(jì)。
=======================================================
=======================================================
===================== ?友 ? 元 ? 函 ? 數(shù) ? =====================
=======================================================
=======================================================
問(wèn)題的提出
我們已知道類(lèi)具有封裝和信息隱藏的特性。只有類(lèi)的成員函數(shù)才能訪問(wèn)類(lèi)的私有成員,程序中的其他函數(shù)是無(wú)法訪問(wèn)私有成員的。非成員函數(shù)可以訪問(wèn)類(lèi)中的公有成員,但是如果將數(shù)據(jù)成員都定義為公有的,這又破壞了隱藏的特性。另外,應(yīng)該看到在某些情況下,特別是在對(duì)某些成員函數(shù)多次調(diào)用時(shí),由于參數(shù)傳遞,類(lèi)型檢查和安全性檢查等都需要時(shí)間開(kāi)銷(xiāo),而影響程序的運(yùn)行效率。
為了解決上述問(wèn)題,提出一種使用友元的方案。友元是一種定義在類(lèi)外部的普通函數(shù),但它需要在類(lèi)體內(nèi)進(jìn)行說(shuō)明,為了與該類(lèi)的成員函數(shù)加以區(qū)別,在說(shuō)明時(shí)前面加以關(guān)鍵字friend。友元不是成員函數(shù),但是它可以訪問(wèn)類(lèi)中的私有成員。友元的作用在于提高程序的運(yùn)行效率,但是,它破壞了類(lèi)的封裝性和隱藏性,使得非成員函數(shù)可以訪問(wèn)類(lèi)的私有成員。
友元可以是一個(gè)函數(shù),該函數(shù)被稱(chēng)為友元函數(shù);友元也可以是一個(gè)類(lèi),該類(lèi)被稱(chēng)為友元類(lèi)。
友元函數(shù)
友元函數(shù)的特點(diǎn)是能夠訪問(wèn)類(lèi)中的私有成員的非成員函數(shù)。友元函數(shù)從語(yǔ)法上看,它與普通函數(shù)一樣,即在定義上和調(diào)用上與普通函數(shù)一樣。下面舉一例子說(shuō)明友元函數(shù)的應(yīng)用。
#include?
#include?
class?Point
{
public:
Point(double?xx,?double?yy)?{?x=xx;?y=yy;?}
void?Getxy();
friend?double?Distance(Point?&a,?Point?&b);
private:
double?x,?y;
};
void?Point::Getxy()
{
cout<<"("<<x<<","<<y<<")"<<endl;< font="">
}
double?Distance(Point?&a,?Point?&b)
{
double?dx?=?a.x?-?b.x;
double?dy?=?a.y?-?b.y;
return?sqrt(dx*dx+dy*dy);
}
void?main()
{
Point?p1(3.0,?4.0),?p2(6.0,?8.0);
p1.Getxy();
p2.Getxy();
double?d?=?Distance(p1,?p2);
cout<<"Distance?is"<<d<<endl;< font="">
}
說(shuō)明:在該程序中的Point類(lèi)中說(shuō)明了一個(gè)友元函數(shù)Distance(),它在說(shuō)明時(shí)前邊加friend關(guān)鍵字,標(biāo)識(shí)它不是成員函數(shù),而是友元函數(shù)。它的定義方法與普通函數(shù)定義一樣,而不同于成員函數(shù)的定義,因?yàn)樗恍枰赋鏊鶎俚念?lèi)。但是,它可以引用類(lèi)中的私有成員,函數(shù)體中a.x,b.x,a.y,b.y都是類(lèi)的私有成員,它們是通過(guò)對(duì)象引用的。在調(diào)用友元函數(shù)時(shí),也是同普通函數(shù)的調(diào)用一樣,不要像成員函數(shù)那樣調(diào)用。本例中,p1.Getxy()和p2.Getxy()這是成員函數(shù)的調(diào)用,要用對(duì)象來(lái)表示。而Distance(p1,?p2)是友元函數(shù)的調(diào)用,它直接調(diào)用,不需要對(duì)象表示,它的參數(shù)是對(duì)象。(該程序的功能是已知兩點(diǎn)坐標(biāo),求出兩點(diǎn)的距離。)
總結(jié)
以上是生活随笔為你收集整理的将类的成员函数作为回调函数(外一篇:友元函数)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 大白菜装系统怎么做 制作大白菜装系统的方
- 下一篇: 提取稳定前景的两种方法