?
Richard zeng? 3/19/2006 10:50:36 AM
?
這幾天又把以前的
C
課程翻了出來(lái)
,
因?yàn)樽约簩?duì)
C
的指針和數(shù)組不是很
DEV.
模擬
C
庫(kù)函數(shù)中的轉(zhuǎn)化大小寫函數(shù)
.
?
//
轉(zhuǎn)換成大寫
,
函數(shù)參數(shù)為字符數(shù)組
//
利用字符串?dāng)?shù)組的結(jié)尾都是
\0
void
ToUpper(chars[])
{
??????
int
i=0;
??????
while(s[i++]!='\0' )
?????? {
????????????? //
判斷是否是小寫字母
?????????????
if(s[i]>='a' && s[i]<='z' )
????????????????????
s[i] -= 32;???? //
小寫字母比大寫字母的
ASCII
大
32
?????? }
}
?
//
轉(zhuǎn)換成大寫
,
函數(shù)參數(shù)為字符指針
void
ToUpperPtr(char* s)
{
??????
while(*s != '\0')
?????? {
//
判斷是否是小寫字母
?????????????
if(*s >='a' && *s <='z')
???????????????????? *s -= 32; ???? //
小寫字母比大寫字母的
ASCII
大
32
?????????????
s++; //
指針的地址
++
?????? }
}
封裝了一下波形顯示,發(fā)現(xiàn)不是很難
WaveShow_src.rar
ASCII碼表大家都很熟悉了吧,利用碼的排列規(guī)律,我們可以很容易的實(shí)現(xiàn)一些操作,比如判斷是否是數(shù)字、大小寫轉(zhuǎn)換等。
這里寫大小寫轉(zhuǎn)換的函數(shù):
char toUpper(const char& ch) { return ch & 0x5F; } char toLower(const char& ch) { return ch | 0x20; } |
函數(shù)原理:大小寫字母的差是32,比如大寫的A是65,小寫的A是97,所以我們把右邊數(shù)第6位置0或者1就能實(shí)現(xiàn)大小寫轉(zhuǎn)換。轉(zhuǎn)換成大寫時(shí),把第6位置0,用ch & 0x5F實(shí)現(xiàn)。轉(zhuǎn)換成小寫時(shí)置1,用ch | 0x20實(shí)現(xiàn)。怎么樣,相當(dāng)?shù)暮?jiǎn)單吧,由此,我們可以寫string類的toUpper和toLower函數(shù)了。^_^,更多技巧盡在探索中。
CMPP協(xié)議的全稱是中國(guó)移動(dòng)通信互聯(lián)網(wǎng)短信網(wǎng)關(guān)接口協(xié)議,它是聯(lián)想亞信公司根據(jù)SMMP協(xié)議為中國(guó)移動(dòng)量身定做的,是符合中國(guó)國(guó)情的一個(gè)短信協(xié)議,閑話不多說(shuō)了,說(shuō)說(shuō)CMPP的主要功能吧。(1)短信發(fā)送(short message mobile originate)MO,就是手機(jī)給SP發(fā)短信;(2)短信接受(short message mobile terminated)MT,這個(gè)就是SP給手機(jī)發(fā)的短信了,通常我們手機(jī)上收到的不良短信就是SP給我們的MT。CMPP協(xié)議的通信基礎(chǔ)是TCP/IP為底層通信承載的,連接方式是長(zhǎng)連接方式。SP與ISMG之間,SMSC和ISMG之間的交互過(guò)程中均采用異步方式,即任一個(gè)網(wǎng)元在收到請(qǐng)求消息后應(yīng)立即回應(yīng)。
下面看看它的消息定義:CMPP中的消息分為消息頭和消息體。消息頭定義如下
字段名 |
字節(jié)數(shù) |
類型 |
描述 |
Total_Length |
4 |
Unsigned Integer |
消息總長(zhǎng)度(含消息頭及消息體) |
Command_Id |
4 |
Unsigned Integer |
命令或響應(yīng)類型 |
Sequence_Id |
4 |
Unsigned Integer |
消息流水號(hào),順序累加,步長(zhǎng)為1,循環(huán)使用(一對(duì)請(qǐng)求和應(yīng)答消息的流水號(hào)必須相同) |
那么下面就是SP連接到ISMG上了,看它的Bind連接消息定義
字段名 |
字節(jié)數(shù) |
屬性 |
描述 |
Source_Addr |
6 |
Octet String |
源地址,此處為SP_Id,即SP的企業(yè)代碼。 |
AuthenticatorSource |
16 |
Octet String |
用于鑒別源地址。其值通過(guò)單向MD5 hash計(jì)算得出,表示如下:
AuthenticatorSource =
MD5(Source_Addr+9 字節(jié)的0 +shared secret+timestamp)
Shared secret 由中國(guó)移動(dòng)與源地址實(shí)體事先商定,timestamp格式為:MMDDHHMMSS,即月日時(shí)分秒,10位。 |
Version |
1 |
Unsigned Integer |
雙方協(xié)商的版本號(hào)(高位4bit表示主版本號(hào),低位4bit表示次版本號(hào)),對(duì)于3.0的版本,高4bit為3,低4位為0 |
Timestamp |
4 |
Unsigned Integer |
時(shí)間戳的明文,由客戶端產(chǎn)生,格式為MMDDHHMMSS,即月日時(shí)分秒,10位數(shù)字的整型,右對(duì)齊 。 |
根據(jù)上的定義我們可以寫出的代碼,如下,在VC環(huán)境下編寫的
/*
*函數(shù)功能:建立和CMPP網(wǎng)關(guān)的直接通路
*輸入條件:SP用戶名const char *UserName,SP密碼const char *PWD
*/
void Ccmpp_API::CmppConnect(const char *UserName, const char *PWD)
{
char netbuf[100];
CMPP_CONNECT *bufer;
bufer=(CMPP_CONNECT*)netbuf;
memset(bufer, 0, 100);
bufer->nTotalLength = htonl(39);//CMPP_CONNECT消息總長(zhǎng)度
bufer->nCommandId = htonl(CMPP_CONNECT_tag);//消息標(biāo)志
//自動(dòng)產(chǎn)生SeqId號(hào)
if (sequenceid == 123456789i32)
{
sequenceid = 1;
}else{
sequenceid++;
}
bufer->nSeqId = htonl(sequenceid);
int MD5Len;
MD5_CTX md5;//MD5源字串
CTime TimeData = CTime::GetCurrentTime();
CString timestamp = TimeData.Format("%m%d%H%M%S");
unsigned char md5source[29];
int Len1 = strlen(UserName);
int Len2 = strlen(PWD);
MD5Len = Len1 + 9 +Len2 + timestamp.GetLength();
memset(md5source, 0, MD5Len);
memcpy(bufer->sSourceAddr, UserName, Len1);
memcpy(md5source, UserName, Len1);
for (int j = 0; j<Len2; j++)
{
md5source[j + Len1 + 9] = PWD[j];
}
for (int i=0;i<timestamp.GetLength();i++)
{
md5source[i + Len2 + Len1 + 9]=timestamp[i];
}
//進(jìn)行md5加密轉(zhuǎn)換
md5.MD5Update(md5source, MD5Len);
md5.MD5Final(md5source);
memcpy(bufer->sAuthSource, md5source, 29);
bufer->cVersion = 0x30;
bufer->nTimeStamp = htonl(atoi(timestamp));
CmppSocket.Send(bufer, 39, 0);//把消息打包發(fā)送
return;
}
今天就到這,下次再寫,歡迎交流!
posted on 2006-03-15 07:58
炙熱的太陽(yáng) 閱讀(38)
評(píng)論(2) 編輯 收藏 收藏至365Key
FeedBack:
2006-03-15 10:38 |
you say:
SP與ISMG之間,SMSC和ISMG之間的交互過(guò)程中均采用異步方式,即任一個(gè)網(wǎng)元在收到請(qǐng)求消息后應(yīng)立即回應(yīng)。
既然是異步方式,就不是收到請(qǐng)求后立即回應(yīng),否則就是同步方式了
據(jù)我所知,CMPP采用的基于滑動(dòng)窗口的異步方式,默認(rèn)情況下可以發(fā)最多16的CMPP package,而不必等待他們的resp.
回復(fù)
2006-03-15 11:21 |
是的,你說(shuō)的沒(méi)有錯(cuò)。
消息是采用并發(fā)方式發(fā)送,加以滑動(dòng)窗口流量控制,窗口大小參數(shù)W可配置,現(xiàn)階段的配置為16,即接收方在應(yīng)答前一次收到的消息最多不超過(guò)16條。這是它們之間的通信方式。
而SP與ISMG之間,SMSC和ISMG之間的交互過(guò)程中均采用異步方式,即任一個(gè)網(wǎng)元在收到請(qǐng)求消息后應(yīng)立即回應(yīng)。這是它們交互過(guò)程中的應(yīng)答方式。即收到一個(gè)消息就應(yīng)該回一個(gè)回應(yīng)消息,而不管對(duì)方是否收到,所以上面講的并沒(méi)有錯(cuò)喲。
回復(fù)
摘要: 最近在VS2005下實(shí)現(xiàn)一個(gè)模版堆棧時(shí),想重載一下輸出運(yùn)算符。結(jié)果老是遇到問(wèn)題,如何都過(guò)不去,想不想去都不明白。還望高手指教。 一開始同樣的程序在VC2005和VC6.0下編譯都沒(méi)問(wèn)題,但是一到鏈接的時(shí)候就出現(xiàn)問(wèn)題了。都提示如下錯(cuò)誤:
error LNK2019: 無(wú)法解析的外部符號(hào) "cla...
閱讀全文
對(duì)于回調(diào)函數(shù)的編寫始終是寫特殊處理功能程序時(shí)用到的技巧之一。先介紹一下回調(diào)的使用基本方法與原理。
1、在這里設(shè):回調(diào)函數(shù)為A()(這是最簡(jiǎn)單的情況,不帶參數(shù),但我們應(yīng)用的實(shí)際情況常常很會(huì)復(fù)雜),使用回調(diào)函數(shù)的操作函數(shù)為B(), 但B函數(shù)是需要參數(shù)的,這個(gè)參數(shù)就是指向函數(shù)A的地址變量,這個(gè)變量一般就是函數(shù)指針。使用方法為:
int A(char *p); // 回調(diào)函數(shù)
typedef int(*CallBack)(char *p) ; // 聲明CallBack 類型的函數(shù)指針
CallBack myCallBack ; // 聲明函數(shù)指針變量
myCallBack = A; // 得到了函數(shù)A的地址
B函數(shù)一般會(huì)寫為 B(CallBack lpCall,char * P,........); // 此處省略了p后的參數(shù)形式 。
所以回調(diào)機(jī)制可解為,函數(shù)B要完成一定功能,但他自己是無(wú)法實(shí)現(xiàn)全部功能的。 需要借助于函數(shù)A來(lái)完成,也就是回調(diào)函數(shù)。B的實(shí)現(xiàn)為:
B(CallBack lpCall,char *pProvide)
{
........... // B 的自己實(shí)現(xiàn)功能語(yǔ)句
lpCall(PpProvide); // 借助回調(diào)完成的功能 ,也就是A函數(shù)來(lái)處理的。
........... // B 的自己實(shí)現(xiàn)功能語(yǔ)句
}
// -------------- 使用例子 -------------
char *p = "hello!";
CallBack myCallBack ;
myCallBack = A ;
B(A, p);
以上就是回調(diào)的基本應(yīng)用,本文所說(shuō)的變身,其實(shí)是利用傳入不同的函數(shù)地址,實(shí)現(xiàn)調(diào)用者類與回調(diào)函數(shù)所在類的不同轉(zhuǎn)換。
1、問(wèn)題描述
CUploadFile 類完成數(shù)據(jù)上傳,與相應(yīng)的界面進(jìn)度顯示。
主要函數(shù)Send(...) 和回調(diào)函數(shù) GetCurState() ;
class CUploadFile : public CDialog
{
......
int Send(LPCTSTR lpServerIP, LPCTSTR lpServerPort, LPCTSTR UploadFilePath) ;
static int GetCurState(int nCurDone, int nInAll, void * pParam) ;
......
}
int CUploadFile ::Send(LPCTSTR lpServerIP, LPCTSTR lpServerPort, LPCTSTR UploadFilePath)
{
... // 導(dǎo)出傳輸數(shù)據(jù)的函數(shù)
int ret = Upload( (LPSTR)(LPCTSTR)m_strData,
GetCurState, // 在這個(gè)回調(diào)函數(shù)中處理界面
this, // CUploadFile 的自身指針 ,也就是pParam 所接受的參數(shù)
(LPSTR)(LPCTSTR)UploadFilePath,
"",
"",
);
}
int CUploadFile ::GetCurState(int nCurData, int nInAll, void * pParam)
{
.........
UploadFile *pThis = (UploadFile *)pParam; // nCurData 當(dāng)前以傳出的數(shù)據(jù)量
// nInAll 總的數(shù)據(jù)量
// 有了pThis可以對(duì)界面進(jìn)行各種操作了。
.............
}
但大家仔細(xì)觀察就可以發(fā)現(xiàn),這個(gè)類把數(shù)據(jù)傳送和界面顯示聚和到了一起,不容易得到復(fù)用。而且在復(fù)用過(guò)程中需要改動(dòng)較多的地方 。
請(qǐng)大家記住現(xiàn)在的回調(diào)函數(shù)傳入的類本身的靜態(tài)成員函數(shù)。
現(xiàn)在我們把數(shù)據(jù)的傳送和界面的顯示分離。回調(diào)則要傳入的是界面處理類的靜態(tài)函數(shù)。
界面處理類 CShowGUI,數(shù)據(jù)上傳類 CUploadData
class CUploadData
{
......
typedef int(*SetUploadCaller)(int nCurData, int nInAll, void * pParam);
int UploadFile(LPCTSTR lpFileNamePath,LPVOID lparam,SetUploadCaller Caller );
// 接受外界出入的參數(shù),主要是回調(diào)函數(shù)的地址通過(guò)參數(shù)Caller,
int Send(LPCTSTR lpServerIP, LPCTSTR lpServerPort, LPCTSTR UploadFilePath) ;
...... // 注意此時(shí)不在需要GetCurState 函數(shù)了 。
}
class CShowGUI: public CDialog
{
.......
typedef int(*SetUploadCaller)(int nCurData, int nInAll, void * pParam);
void SetCallBack(LPCTSTR strPath);
static int GetCurState(int nCurData, int nInAll, void * pParam) ;
CUploadData m_Uploa
d ; // 數(shù)據(jù)上傳類是界面顯示類的一個(gè)成員變量。
.......
}
void CShowGUI :: SetCallBack(LPCTSTR strPath)
{
CUploadData myUploadData ;
SetUploadCaller myCaller; // 聲明一個(gè)函數(shù)指針變量
myCaller = CurState ; // 取得界面處理函數(shù)的地址
myUploadData .UploadFile(strPath,this,myCaller); // 界面處理類的函數(shù)傳入,實(shí)現(xiàn)了數(shù)據(jù)傳入與界面處理的分離 .
}
通過(guò)上面的演示做到了界面與數(shù)據(jù)的分離,回調(diào)函數(shù)分別扮演了不同角色,所以隨著處理問(wèn)題的不同應(yīng)靈活應(yīng)用,但同樣因?yàn)樘幚頂?shù)據(jù)類不知道界面處理類或外部調(diào)用類的類型,而更無(wú)法靈活地處理界面的不同顯示方式。這方面還希望喜歡鉆研技術(shù)的朋友繼續(xù)研究。
指針,在C/C++語(yǔ)言中一直是很受寵的;幾乎找不到一個(gè)不使用指針的C/C++應(yīng)用。用于存儲(chǔ)數(shù)據(jù)和程序的地址,這是指針的基本功能。用于指向整型數(shù),用整數(shù)指針(int*);指向浮點(diǎn)數(shù)用浮點(diǎn)數(shù)指針(float*);指向結(jié)構(gòu),用對(duì)應(yīng)的結(jié)構(gòu)指針(struct xxx *);指向任意地址,用無(wú)類型指針(void*)。
有時(shí)候,我們需要一些通用的指針。在C語(yǔ)言當(dāng)中,(void*) 可以代表一切;但是在C++中,我們還有一些比較特殊的指針,無(wú)法用(void*)來(lái)表示。事實(shí)上,在C++中,想找到一個(gè)通用的指針,特別是通用的函數(shù)指針簡(jiǎn)直是一個(gè)“不可能任務(wù)”。
C++是一種靜態(tài)類型的語(yǔ)言,類型安全在C++中舉足輕重。在C語(yǔ)言中,你可以用void*來(lái)指向一切;但在C++中,void*并不能指向一切,就算能,也失去了類型安全的意義了。類型安全往往能幫我們找出程序中潛在的一些BUG。
下面我們來(lái)探討一下,C++中如何存儲(chǔ)各種類型數(shù)據(jù)的指針。
C++指針探討 (一)數(shù)據(jù)指針 沐楓網(wǎng)志 1. 數(shù)據(jù)指針
數(shù)據(jù)指針?lè)譃閮煞N:常規(guī)數(shù)據(jù)指針和成員數(shù)據(jù)指針
1.1 常規(guī)數(shù)據(jù)指針
這個(gè)不用說(shuō)明了,和C語(yǔ)言一樣,定義、賦值是很簡(jiǎn)單明了的。常見(jiàn)的有:int*, double* 等等。
如:
int value = 123;
int * pn = &value;
1.2 成員數(shù)據(jù)指針
有如下的結(jié)構(gòu):
struct MyStruct
{
int key;
int value;
};
現(xiàn)在有一個(gè)結(jié)構(gòu)對(duì)象:
MyStruct me;
MyStruct* pMe = &me;
我們需要 value 成員的地址,我們可以:
int * pValue = &me.value;
//或
int * pValue = &pMe->value;
當(dāng)然了,這個(gè)指針仍然是屬于第一種范籌----常規(guī)數(shù)據(jù)指針。
好了,我們現(xiàn)在需要一種指針,它指向MyStruct中的任一數(shù)據(jù)成員,那么它應(yīng)該是這樣的子:
int MyStruct::* pMV = &MyStruct::value;
//或
int MyStruct::* pMK = &MyStruct::key;
這種指針的用途是用于取得結(jié)構(gòu)成員在結(jié)構(gòu)內(nèi)的地址。我們可以通過(guò)該指針來(lái)訪問(wèn)成員數(shù)據(jù):
int value = pMe->*pMV; // 取得pMe的value成員數(shù)據(jù)。
int key = me.*pMK; // 取得me的key成員數(shù)據(jù)。
那么,在什么場(chǎng)合下會(huì)使用到成員數(shù)據(jù)指針呢?
確實(shí),成員指針本來(lái)就不是一種很常用的指針。不過(guò),在某些時(shí)候還是很有用處的。我們先來(lái)看看下面的一個(gè)函數(shù):
int sum(MyStruct* objs, int MyStruct::* pm, int count)
{
int result = 0;
for(int i = 0; i < count; ++i)
result += objs[i].*pm;
return result;
}
這個(gè)函數(shù)的功能是什么,你能看明白嗎?它的功能就是,給定count個(gè)MyStruct結(jié)構(gòu)的指針,計(jì)算出給定成員數(shù)據(jù)的總和。有點(diǎn)拗口對(duì)吧?看看下面的程序,你也許就明白了:
MyStruct me[10] =
{
{1,2},{3,4},{5,6},{7,8},{9,10},{11,12},{13,14},{15,16},{17,18},{19,20}
};
int sum_value = sum(me, &MyStruct::value, 10);
//計(jì)算10個(gè)MyStruct結(jié)構(gòu)的value成員的總和: sum_value 值 為 110 (2+4+6+8+
+20)
int sum_key = sum(me, &MyStruct::key, 10);
//計(jì)算10個(gè)MyStruct結(jié)構(gòu)的key成員的總和: sum_key 值 為 100 (1+3+5+7+
+19)
也許,你覺(jué)得用常規(guī)指針也可以做到,而且更易懂。Ok,沒(méi)問(wèn)題:
int sum(MyStruct* objs, int count)
{
int result = 0;
for(int i = 0; i < count; ++i)
result += objs[i].value;
return result;
}
你是想這么做嗎?但這么做,你只能計(jì)算value,如果要算key的話,你要多寫一個(gè)函數(shù)。有多少個(gè)成員需要計(jì)算的話,你就要寫多少個(gè)函數(shù),多麻煩啊。
C語(yǔ)言的指針相當(dāng)?shù)撵`活方便,但也相當(dāng)容易出錯(cuò)。許多C語(yǔ)言初學(xué)者,甚至C語(yǔ)言老鳥都很容易栽倒在C語(yǔ)言的指針下。但不可否認(rèn)的是,指針在C語(yǔ)言中的位置極其重要,也許可以偏激一點(diǎn)的來(lái)說(shuō):沒(méi)有指針的C程序不是真正的C程序。
然而C++的指針卻常常給我一種束手束腳的感覺(jué)。C++比C語(yǔ)言有更嚴(yán)格的靜態(tài)類型,更加強(qiáng)調(diào)類型安全,強(qiáng)調(diào)編譯時(shí)檢查。因此,對(duì)于C語(yǔ)言中最容易錯(cuò)用的指針,更是不能放過(guò):C++的指針被分成數(shù)據(jù)指針,數(shù)據(jù)成員指針,函數(shù)指針,成員函數(shù)指針,而且不能隨便相互轉(zhuǎn)換。而且這些指針的聲明格式都不一樣:
數(shù)據(jù)指針 |
T * |
成員數(shù)據(jù)指針 |
T::* |
函數(shù)指針 |
R (*)(...) |
成員函數(shù)指針 |
R (T::*)(...) |
盡管C++中仍然有萬(wàn)能指針void*,但它卻屬于被批斗的對(duì)象,而且再也不能“萬(wàn)能”了。它不能轉(zhuǎn)換成成員指針。
這樣一來(lái),C++的指針就變得很尷尬:我們需要一種指針能夠指向同一類型的數(shù)據(jù),不管這個(gè)數(shù)據(jù)是普通數(shù)據(jù),還是成員數(shù)據(jù);我們更需要一種指針能夠指向同一類型的函數(shù),不管這個(gè)函數(shù)是靜態(tài)函數(shù),還是成員函數(shù)。但是沒(méi)有,至少?gòu)默F(xiàn)在的C++標(biāo)準(zhǔn)中,還沒(méi)有看到。
沐楓網(wǎng)志 C++指針探討(三)成員函數(shù)指針
自從有了類,我們開始按照 數(shù)據(jù)+操作 的方式來(lái)組織數(shù)據(jù)結(jié)構(gòu);自從有了模板,我們又開始把 數(shù)據(jù) 和 算法 分離,以便重用,實(shí)在夠折騰人的。但不管怎么折騰,現(xiàn)在大多數(shù)函數(shù)都不再單身,都嫁給了類,進(jìn)了圍城。可是我們?nèi)匀恍枰軌蜃杂烧{(diào)用這些成員函數(shù)。
考慮一下windows下的定時(shí)調(diào)用。SetTimer函數(shù)的原型是這樣的:
UINT_PTR SetTimer(
HWND hWnd,
UINT_PTR nIDEvent,
UINT uElapse,
TIMERPROC lpTimerFunc
);

其中,參數(shù)就不解釋了,這個(gè)函數(shù)估計(jì)大多數(shù)windows開發(fā)人員都知道。lpTimerFunc是個(gè)會(huì)被定時(shí)調(diào)用的函數(shù)指針。假如我們不通過(guò)WM_TIMER消息來(lái)觸發(fā)定時(shí)器,而是通過(guò)lpTimerFunc來(lái)定時(shí)工作,那么我們就只能使用普通函數(shù)或靜態(tài)函數(shù),而無(wú)論如何都不能使用成員函數(shù),哪怕通過(guò)靜態(tài)函數(shù)轉(zhuǎn)調(diào)也不行。
再考慮一下線程的創(chuàng)建:
uintptr_t _beginthread(
void( *start_address )( void * ),
unsigned stack_size,
void *arglist
);
start_address仍然只支持普通函數(shù)。不過(guò)這回好了,它允許回調(diào)函數(shù)一個(gè)void*參數(shù),它將會(huì)arglist作為參數(shù)來(lái)調(diào)用start_address。于是,聰明的C++程序員,就利用arglist傳遞this指針,從而利用靜態(tài)函數(shù)成功的調(diào)用到了成員函數(shù)了:
class mythread


{
public:
static void doit(void* pThis)

{
((mythread*)pThis)->doit();
}

void doit()
{
}
};

main()


{

mythread* pmt = new mythread;
_beginthread(&mythread::doit, 0, (void*)pmt);

}
但是顯然,C++程序員肯定不會(huì)因此而滿足。這里頭有許多被C++批判的不安定因素。它使用了C++中被認(rèn)為不安全的類型轉(zhuǎn)換,不安全的void*指針,等等等等。但這是系統(tǒng)為C語(yǔ)言留下的調(diào)用接口,這也就認(rèn)了。那么假如,我們就在C++程序中如何來(lái)調(diào)用成員函數(shù)指針呢?
如下例,我們打算對(duì)vector中的所有類調(diào)用其指定的成員函數(shù):
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;

class A


{
int value;
public:

A(int v)
{value = v;}

void doit()
{ cout << value << endl;};
static void call_doit(A& rThis)

{
rThis.doit();
}
};


int main()


{
vector<A> va;
va.push_back(A(1));
va.push_back(A(2));
va.push_back(A(3));
va.push_back(A(4));
//方法1:
//for_each(va.begin(), va.end(), &A::doit); //error
//方法2:
for_each(va.begin(), va.end(), &A::call_doit);
//方法3:
for_each(va.begin(), va.end(), mem_fun_ref<void, A>(&A::doit));

system("Pause");

return 0;
}

方法1,編譯不能通過(guò)。for_each只允許具有一個(gè)參數(shù)的函數(shù)指針或函數(shù)對(duì)象,哪怕A::doit默認(rèn)有一個(gè)this指針參數(shù)也不行。不是for_each沒(méi)考慮到這一點(diǎn),而是根本做不到!
方法2,顯然是受到了beginthread的啟發(fā),使用一個(gè)靜態(tài)函數(shù)來(lái)轉(zhuǎn)調(diào)用,哈哈成功了。但是不爽!這不是C++。
方法3,呼,好不容易啊,終于用mem_fun_ref包裝成功了成員函數(shù)指針。
似乎方法3不錯(cuò),又是類型安全的,又可以通用--慢著,首先,它很丑,哪有調(diào)用普通C函數(shù)指針那么漂亮啊(見(jiàn)方法2),用了一大串包裝,又是尖括號(hào)又是圓括號(hào),還少不了&號(hào)!其次,它只能包裝不超過(guò)一個(gè)參數(shù)的函數(shù)!盡管它在for_each中夠用了,但是你要是想用在超過(guò)一個(gè)參數(shù)的場(chǎng)合,那只有一句話:不可能的任務(wù)。
是的,在標(biāo)準(zhǔn)C++中,這是不可能的任務(wù)。但事情并不總是悲觀的,至少有許多第三方庫(kù)提供了超越mem_fun的包裝。如boost::function等等。但是它也有限制:它所支持的參數(shù)仍然是有限的,只有十多個(gè),盡管夠你用的了;同樣,它也是丑陋的,永遠(yuǎn)不要想它能夠簡(jiǎn)單的用&來(lái)搞定。
也許,以失去美麗的代價(jià),來(lái)?yè)Q取質(zhì)量上的保證,這也是C++對(duì)于函數(shù)指針的一種無(wú)奈吧……
期待C++0x版本。它通過(guò)可變模板參數(shù),能夠讓mem_fun的參數(shù)達(dá)到無(wú)限個(gè)……
--------
BTW: C++Builder擴(kuò)展了一個(gè)關(guān)鍵字 closure ,允許成員函數(shù)指針如同普通函數(shù)指針一樣使用。也許C++0x能考慮一下……
摘要: 1 2 #ifndef _BITMAP_H 3 #define _BITMAP_H 4 5 #include <windows.h> 6 7 void SaveImage(const char ...
閱讀全文