• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Beginning to 編程

            VC++ 方面編程文章

             

            轉換大小寫C函數

            ?

            Richard zeng? 3/19/2006 10:50:36 AM

            ?

            這幾天又把以前的 C 課程翻了出來 , 因為自己對 C 的指針和數組不是很 DEV.

            模擬 C 庫函數中的轉化大小寫函數 .

            ?

            // 轉換成大寫 , 函數參數為字符數組

            // 利用字符串數組的結尾都是 \0

            void ToUpper(chars[])

            {

            ?????? int i=0;

            ?????? while(s[i++]!='\0' )

            ?????? {

            ????????????? // 判斷是否是小寫字母

            ????????????? if(s[i]>='a' && s[i]<='z' )

            ???????????????????? s[i] -= 32;???? // 小寫字母比大寫字母的 ASCII 32

            ?????? }

            }

            ?

            // 轉換成大寫 , 函數參數為字符指針

            void ToUpperPtr(char* s)

            {

            ?????? while(*s != '\0')

            ?????? {

            // 判斷是否是小寫字母

            ????????????? if(*s >='a' && *s <='z')

            ???????????????????? *s -= 32; ???? // 小寫字母比大寫字母的 ASCII 32

            ????????????? s++; // 指針的地址 ++

            ?????? }

            }

            posted @ 2006-03-19 10:56 Beginning to 編程 閱讀(5851) | 評論 (5)編輯 收藏

            波形顯示不是很難 /zhuan

            封裝了一下波形顯示,發現不是很難


            WaveShow_src.rar

            posted @ 2006-03-16 11:00 Beginning to 編程 閱讀(619) | 評論 (1)編輯 收藏

            大小寫轉換的方法【C/C++】 /zhuan

            ASCII碼表大家都很熟悉了吧,利用碼的排列規律,我們可以很容易的實現一些操作,比如判斷是否是數字、大小寫轉換等。
            這里寫大小寫轉換的函數:
            char toUpper(const char& ch)
            {
                return ch & 0x5F;
            }
            char toLower(const char& ch)
            {
                return ch | 0x20;
            }
             
            函數原理:大小寫字母的差是32,比如大寫的A是65,小寫的A是97,所以我們把右邊數第6位置0或者1就能實現大小寫轉換。轉換成大寫時,把第6位置0,用ch & 0x5F實現。轉換成小寫時置1,用ch | 0x20實現。怎么樣,相當的簡單吧,由此,我們可以寫string類的toUpper和toLower函數了。^_^,更多技巧盡在探索中。

            posted @ 2006-03-15 13:31 Beginning to 編程 閱讀(956) | 評論 (0)編輯 收藏

            淺談CMPP協議(一) /zhuan

                CMPP協議的全稱是中國移動通信互聯網短信網關接口協議,它是聯想亞信公司根據SMMP協議為中國移動量身定做的,是符合中國國情的一個短信協議,閑話不多說了,說說CMPP的主要功能吧。(1)短信發送(short message mobile originate)MO,就是手機給SP發短信;(2)短信接受(short message mobile terminated)MT,這個就是SP給手機發的短信了,通常我們手機上收到的不良短信就是SP給我們的MT。CMPP協議的通信基礎是TCP/IP為底層通信承載的,連接方式是長連接方式。SP與ISMG之間,SMSC和ISMG之間的交互過程中均采用異步方式,即任一個網元在收到請求消息后應立即回應。
               下面看看它的消息定義:CMPP中的消息分為消息頭和消息體。消息頭定義如下
             
             

            字段名

            字節數

            類型

            描述

            Total_Length  

            4

            Unsigned Integer

            消息總長度(含消息頭及消息體)

            Command_Id

            4

            Unsigned Integer

            命令或響應類型

            Sequence_Id

            4

            Unsigned Integer

            消息流水號,順序累加,步長為1,循環使用(一對請求和應答消息的流水號必須相同)

             
            那么下面就是SP連接到ISMG上了,看它的Bind連接消息定義
             

            字段名

            字節數

            屬性

            描述

            Source_Addr 

            6

            Octet String

            源地址,此處為SP_Id,即SP的企業代碼。

            AuthenticatorSource

            16

            Octet String

            用于鑒別源地址。其值通過單向MD5 hash計算得出,表示如下:

            AuthenticatorSource =

            MD5Source_Addr+9 字節的0 +shared secret+timestamp

            Shared secret 由中國移動與源地址實體事先商定,timestamp格式為:MMDDHHMMSS,即月日時分秒,10位。

            Version

            1

            Unsigned Integer

            雙方協商的版本號(高位4bit表示主版本號,低位4bit表示次版本號),對于3.0的版本,高4bit3,低4位為0

            Timestamp

            4

            Unsigned Integer

            時間戳的明文,由客戶端產生,格式為MMDDHHMMSS,即月日時分秒,10位數字的整型,右對齊

             
            根據上的定義我們可以寫出的代碼,如下,在VC環境下編寫的

            /*
             *函數功能:建立和CMPP網關的直接通路
             *輸入條件: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消息總長度
             bufer->nCommandId = htonl(CMPP_CONNECT_tag);//消息標志
             //自動產生SeqId號
                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];
             }
             
             //進行md5加密轉換
             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);//把消息打包發送
             return;
            }
             
            今天就到這,下次再寫,歡迎交流!
            posted on 2006-03-15 07:58 炙熱的太陽 閱讀(38) 評論(2)  編輯 收藏 收藏至365Key


            FeedBack:

            # re: 淺談CMPP協議(一)
            2006-03-15 10:38 | 小明
            you say:
            SP與ISMG之間,SMSC和ISMG之間的交互過程中均采用異步方式,即任一個網元在收到請求消息后應立即回應。

            既然是異步方式,就不是收到請求后立即回應,否則就是同步方式了

            據我所知,CMPP采用的基于滑動窗口的異步方式,默認情況下可以發最多16的CMPP package,而不必等待他們的resp.  回復
              
            # re: 淺談CMPP協議(一)
            2006-03-15 11:21 | 炙熱的太陽
            是的,你說的沒有錯。

            消息是采用并發方式發送,加以滑動窗口流量控制,窗口大小參數W可配置,現階段的配置為16,即接收方在應答前一次收到的消息最多不超過16條。這是它們之間的通信方式。

            而SP與ISMG之間,SMSC和ISMG之間的交互過程中均采用異步方式,即任一個網元在收到請求消息后應立即回應。這是它們交互過程中的應答方式。即收到一個消息就應該回一個回應消息,而不管對方是否收到,所以上面講的并沒有錯喲。


              回復

            posted @ 2006-03-15 12:25 Beginning to 編程 閱讀(877) | 評論 (0)編輯 收藏

            為什么在VS2005重載輸出運算符那么難 /zhuan

                 摘要: 最近在VS2005下實現一個模版堆棧時,想重載一下輸出運算符。結果老是遇到問題,如何都過不去,想不想去都不明白。還望高手指教。  一開始同樣的程序在VC2005和VC6.0下編譯都沒問題,但是一到鏈接的時候就出現問題了。都提示如下錯誤:       error LNK2019: 無法解析的外部符號 "cla...  閱讀全文

            posted @ 2006-03-15 11:57 Beginning to 編程 閱讀(1121) | 評論 (1)編輯 收藏

            VC中回調函數使用的變身大法 /zhuan

            對于回調函數的編寫始終是寫特殊處理功能程序時用到的技巧之一。先介紹一下回調的使用基本方法與原理。

              1、在這里設:回調函數為A()(這是最簡單的情況,不帶參數,但我們應用的實際情況常常很會復雜),使用回調函數的操作函數為B(), 但B函數是需要參數的,這個參數就是指向函數A的地址變量,這個變量一般就是函數指針。使用方法為:

            int A(char *p); // 回調函數
            typedef int(*CallBack)(char *p) ; // 聲明CallBack 類型的函數指針
            CallBack myCallBack ; // 聲明函數指針變量
            myCallBack = A; // 得到了函數A的地址

              B函數一般會寫為 B(CallBack lpCall,char * P,........); // 此處省略了p后的參數形式 。

              所以回調機制可解為,函數B要完成一定功能,但他自己是無法實現全部功能的。 需要借助于函數A來完成,也就是回調函數。B的實現為:

            B(CallBack lpCall,char *pProvide)
            {
             ........... // B 的自己實現功能語句
             lpCall(PpProvide); // 借助回調完成的功能 ,也就是A函數來處理的。
             ........... // B 的自己實現功能語句
            }
            // -------------- 使用例子 -------------
            char *p = "hello!";
            CallBack myCallBack ;
            myCallBack = A ;
            B(A, p);

              以上就是回調的基本應用,本文所說的變身,其實是利用傳入不同的函數地址,實現調用者類與回調函數所在類的不同轉換。

              1、問題描述

              CUploadFile 類完成數據上傳,與相應的界面進度顯示。

              主要函數Send(...) 和回調函數 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)
            {
             ... // 導出傳輸數據的函數
             int ret = Upload( (LPSTR)(LPCTSTR)m_strData,
                GetCurState, // 在這個回調函數中處理界面
                this, // CUploadFile 的自身指針 ,也就是pParam 所接受的參數
                (LPSTR)(LPCTSTR)UploadFilePath,
                "",
                "",
             );
            }
            int CUploadFile ::GetCurState(int nCurData, int nInAll, void * pParam)
            {
             .........
             UploadFile *pThis = (UploadFile *)pParam; // nCurData 當前以傳出的數據量
             // nInAll 總的數據量
             // 有了pThis可以對界面進行各種操作了。
             .............
            }

              但大家仔細觀察就可以發現,這個類把數據傳送和界面顯示聚和到了一起,不容易得到復用。而且在復用過程中需要改動較多的地方 。

              請大家記住現在的回調函數傳入的類本身的靜態成員函數。

              現在我們把數據的傳送和界面的顯示分離。回調則要傳入的是界面處理類的靜態函數。

              界面處理類 CShowGUI,數據上傳類 CUploadData

            class CUploadData
            {
             ......
             typedef int(*SetUploadCaller)(int nCurData, int nInAll, void * pParam);
             int UploadFile(LPCTSTR lpFileNamePath,LPVOID lparam,SetUploadCaller Caller );
             // 接受外界出入的參數,主要是回調函數的地址通過參數Caller,
             int Send(LPCTSTR lpServerIP, LPCTSTR lpServerPort, LPCTSTR UploadFilePath) ;
             ...... // 注意此時不在需要GetCurState 函數了 。
            }

            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 ; // 數據上傳類是界面顯示類的一個成員變量。
             .......
            }

            void CShowGUI :: SetCallBack(LPCTSTR strPath)
            {
             CUploadData myUploadData ;
             SetUploadCaller myCaller; // 聲明一個函數指針變量
             myCaller = CurState ; // 取得界面處理函數的地址
             myUploadData .UploadFile(strPath,this,myCaller); // 界面處理類的函數傳入,實現了數據傳入與界面處理的分離 .
            }

              通過上面的演示做到了界面與數據的分離,回調函數分別扮演了不同角色,所以隨著處理問題的不同應靈活應用,但同樣因為處理數據類不知道界面處理類或外部調用類的類型,而更無法靈活地處理界面的不同顯示方式。這方面還希望喜歡鉆研技術的朋友繼續研究。陳剛

            posted @ 2006-03-14 17:33 Beginning to 編程 閱讀(325) | 評論 (0)編輯 收藏

            C++指針探討 (二) 函數指針 /zhuan

            在C/C++中,數據指針是最直接,也最常用的,因此,理解起來也比較容易。而函數指針,作為運行時動態調用(比如回調函數 CallBack Function)是一種常見的,而且是很好用的手段。

              我們先簡單的說一下函數指針。(這一部份沒什么價值,純是為了引出下一節的內容)
               
             2 常規函數指針

                    void(*fp)();

              fp 是一個典型的函數指針,用于指向無參數,無返回值的函數。

                    void(*fp2)(int);

              fp2 也是一個函數指針,用于指向有一個整型參數,無返回值的函數。
              當然,有經驗人士一般都會建議使用typedef來定義函數指針的類型,如:

                    typedef void(* FP)();
                    FP fp3; 
            // 和上面的fp一樣的定義。

              函數指針之所以讓初學者畏懼,最主要的原因是它的括號太多了;某些用途的函數指針,往往會讓人陷在括號堆中出不來,這里就不舉例了,因為不是本文討論的范圍;typedef 方法可以有效的減少括號的數量,以及理清層次,所以受到推薦。本文暫時只考慮簡單的函數指針,因此暫不用到typedef。

              假如有如下兩個函數:

              void f1()
              
            {
                  std::cout 
            << "call f " << std::endl;
              }

              
              
            void f2(int a)
              
            {
                  std::cout 
            << "call f2( " << a << " )" << std::endl;
              }

              現在需要通過函數指針來調用,我們需要給指針指定函數:

              fp = &f1; // 也可以用:fp = f1;
              fp2= &f2; // 也可以用:fp2= f2;
              void (*fp3)() = &f1; // 也可以用:void (*fp3)() = f1;  
              
            //調用時如下:
              fp(); // 或 (*fp)();
              fp2(1); // 或 (*fp2)(1);
              fp3();  // 或 (*fp3)();

              對于此兩種調用方法,效果完全一樣,我推薦用前一種。后一種不僅僅是多打了鍵盤,而且也損失了一些靈活性。這里暫且不說它。
              
              C++強調類型安全。也就是說,不同類型的變量是不能直接賦值的,否則輕則警告,重則報錯。這是一個很有用的特性,常常能幫我們找到問題。因此,有識之士認為,C++中的任何一外警告都不能忽視。甚至有人提出,編譯的時候不能出現任何警告信息,也就是說,警告應該當作錯誤一樣處理。
              
              比如,我們把f1賦值給fp2,那么C++編譯器(vc7.1)就會報錯:

              fp2 = &f1; // error C2440: “=” : 無法從“void (__cdecl *)(void)”轉換為“void (__cdecl *)(int)”
              fp1 = &f1; // OK

              這樣,編譯器可以幫我們找出編碼上的錯誤,節省了我們的排錯時間。
              
              考慮一下C++標準模板庫的sort函數:

              // 快速排序函數
              template<typename RandomAccessIterator, typename BinaryPredicate>
                 
            void sort(
                    RandomAccessIterator _First, 
            // 需排序數據的第一個元素位置
                    RandomAccessIterator _Last,  // 需排序數據的最后一個元素位置(不參與排序)
                    BinaryPredicate _Comp     // 排序使用的比較算法(可以是函數指針、函數對象等)
                 );

              比如,我們有一個整型數組:

              int n[5= {3,2,1,8,9};

              要對它進行升序排序,我們需定義一個比較函數:

              bool less(int a, int b)
              
            {
                  
            return a < b; 
              }

              然后用:

              sort(n, n+5, less);

              要是想對它進行降序排序,我們只要換一個比較函數就可以了。C/C++的標準模板已經提供了less和great函數,因此我們可以直接用下面的語句來比較:  

              sort(n, n+5, great);


              這樣,不需要改變sort函數的定義,就可以按任意方法進行排序,是不是很靈活?  
              這種用法以C++的標準模板庫(STL)中非常流行。另外,操作系統中也經常使用回調(CallBack)函數,實際上,所謂回調函數,本質就是函數指針。

              看起來很簡單吧,這是最普通的C語言指針的用法。本來這是一個很美妙的事情,但是當C++來臨時,世界就開始變了樣。
              假如,用來進行sort的比較函數是某個類的成員,那又如何呢?

            posted @ 2006-03-14 16:44 Beginning to 編程 閱讀(333) | 評論 (0)編輯 收藏

            C++指針探討 (一)數據指針 /zhuan

              指針,在C/C++語言中一直是很受寵的;幾乎找不到一個不使用指針的C/C++應用。用于存儲數據和程序的地址,這是指針的基本功能。用于指向整型數,用整數指針(int*);指向浮點數用浮點數指針(float*);指向結構,用對應的結構指針(struct xxx *);指向任意地址,用無類型指針(void*)。
                有時候,我們需要一些通用的指針。在C語言當中,(void*) 可以代表一切;但是在C++中,我們還有一些比較特殊的指針,無法用(void*)來表示。事實上,在C++中,想找到一個通用的指針,特別是通用的函數指針簡直是一個“不可能任務”。
               
                C++是一種靜態類型的語言,類型安全在C++中舉足輕重。在C語言中,你可以用void*來指向一切;但在C++中,void*并不能指向一切,就算能,也失去了類型安全的意義了。類型安全往往能幫我們找出程序中潛在的一些BUG。
               
                下面我們來探討一下,C++中如何存儲各種類型數據的指針。

            C++指針探討 (一)數據指針      沐楓網志
               
                1.  數據指針
                 數據指針分為兩種:常規數據指針和成員數據指針
                 
                1.1 常規數據指針
                 這個不用說明了,和C語言一樣,定義、賦值是很簡單明了的。常見的有:int*, double* 等等。
                 如:
                 int value = 123;
                 
            int * pn = &value;
               
                 
                1.2 成員數據指針
                 有如下的結構:
                 struct MyStruct
                 {
                   
            int key;
                   
            int value;
                 };
               
                 現在有一個結構對象:
                 MyStruct me;
                 MyStruct* pMe = &me;
               
                 我們需要 value 成員的地址,我們可以:
                 int * pValue = &me.value;
                 //
                 int * pValue = &pMe->value;
               
                 當然了,這個指針仍然是屬于第一種范籌----常規數據指針。
                 
                 好了,我們現在需要一種指針,它指向MyStruct中的任一數據成員,那么它應該是這樣的子:
                 int MyStruct::* pMV = &MyStruct::value;
                 
            //
                 int MyStruct::* pMK = &MyStruct::key;
               
                 這種指針的用途是用于取得結構成員在結構內的地址。我們可以通過該指針來訪問成員數據:
                 int value = pMe->*pMV; // 取得pMe的value成員數據。
                 int key = me.*pMK; // 取得me的key成員數據。
               
                 那么,在什么場合下會使用到成員數據指針呢?
                 確實,成員指針本來就不是一種很常用的指針。不過,在某些時候還是很有用處的。我們先來看看下面的一個函數:
              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;
              }
                 
                 這個函數的功能是什么,你能看明白嗎?它的功能就是,給定count個MyStruct結構的指針,計算出給定成員數據的總和。有點拗口對吧?看看下面的程序,你也許就明白了:
                 
                 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);
                 
            //計算10個MyStruct結構的value成員的總和: sum_value 值 為 110     (2+4+6+8++20)
                 
                 
            int sum_key = sum(me, &MyStruct::key, 10);
                 
            //計算10個MyStruct結構的key成員的總和:   sum_key 值 為 100       (1+3+5+7++19)
               
                 
                 也許,你覺得用常規指針也可以做到,而且更易懂。Ok,沒問題:
                 int sum(MyStruct* objs, int count)
                 {
                  
            int result = 0;
                  
            for(int i = 0; i < count; ++i)
                   result 
            += objs[i].value;
                  
            return result;
                 }

                 你是想這么做嗎?但這么做,你只能計算value,如果要算key的話,你要多寫一個函數。有多少個成員需要計算的話,你就要寫多少個函數,多麻煩啊。

            posted @ 2006-03-14 16:43 Beginning to 編程 閱讀(178) | 評論 (0)編輯 收藏

            C++指針探討 (三) 成員函數指針 /zhuan

            C語言的指針相當的靈活方便,但也相當容易出錯。許多C語言初學者,甚至C語言老鳥都很容易栽倒在C語言的指針下。但不可否認的是,指針在C語言中的位置極其重要,也許可以偏激一點的來說:沒有指針的C程序不是真正的C程序。
              然而C++的指針卻常常給我一種束手束腳的感覺。C++比C語言有更嚴格的靜態類型,更加強調類型安全,強調編譯時檢查。因此,對于C語言中最容易錯用的指針,更是不能放過:C++的指針被分成數據指針,數據成員指針,函數指針,成員函數指針,而且不能隨便相互轉換。而且這些指針的聲明格式都不一樣:

            數據指針 T *
            成員數據指針 T::*
            函數指針 R (*)(...)
            成員函數指針 R (T::*)(...)

              盡管C++中仍然有萬能指針void*,但它卻屬于被批斗的對象,而且再也不能“萬能”了。它不能轉換成成員指針。

              這樣一來,C++的指針就變得很尷尬:我們需要一種指針能夠指向同一類型的數據,不管這個數據是普通數據,還是成員數據;我們更需要一種指針能夠指向同一類型的函數,不管這個函數是靜態函數,還是成員函數。但是沒有,至少從現在的C++標準中,還沒有看到。
             
            沐楓網志 C++指針探討(三)成員函數指針

              自從有了類,我們開始按照 數據+操作 的方式來組織數據結構;自從有了模板,我們又開始把 數據 和 算法 分離,以便重用,實在夠折騰人的。但不管怎么折騰,現在大多數函數都不再單身,都嫁給了類,進了圍城。可是我們仍然需要能夠自由調用這些成員函數。
              考慮一下windows下的定時調用。SetTimer函數的原型是這樣的:

            UINT_PTR SetTimer(
                HWND hWnd,
                UINT_PTR nIDEvent,
                UINT uElapse,
                TIMERPROC lpTimerFunc
            );
              其中,參數就不解釋了,這個函數估計大多數windows開發人員都知道。lpTimerFunc是個會被定時調用的函數指針。假如我們不通過WM_TIMER消息來觸發定時器,而是通過lpTimerFunc來定時工作,那么我們就只能使用普通函數或靜態函數,而無論如何都不能使用成員函數,哪怕通過靜態函數轉調也不行。

              再考慮一下線程的創建:
            uintptr_t _beginthread( 
               
            void*start_address )( void * ),
               unsigned stack_size,
               
            void *arglist 
            );
              start_address仍然只支持普通函數。不過這回好了,它允許回調函數一個void*參數,它將會arglist作為參數來調用start_address。于是,聰明的C++程序員,就利用arglist傳遞this指針,從而利用靜態函數成功的調用到了成員函數了:
            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++程序員肯定不會因此而滿足。這里頭有許多被C++批判的不安定因素。它使用了C++中被認為不安全的類型轉換,不安全的void*指針,等等等等。但這是系統為C語言留下的調用接口,這也就認了。那么假如,我們就在C++程序中如何來調用成員函數指針呢?
              如下例,我們打算對vector中的所有類調用其指定的成員函數:

            #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,編譯不能通過。for_each只允許具有一個參數的函數指針或函數對象,哪怕A::doit默認有一個this指針參數也不行。不是for_each沒考慮到這一點,而是根本做不到!
              方法2,顯然是受到了beginthread的啟發,使用一個靜態函數來轉調用,哈哈成功了。但是不爽!這不是C++。
              方法3,呼,好不容易啊,終于用mem_fun_ref包裝成功了成員函數指針。
              似乎方法3不錯,又是類型安全的,又可以通用--慢著,首先,它很丑,哪有調用普通C函數指針那么漂亮啊(見方法2),用了一大串包裝,又是尖括號又是圓括號,還少不了&號!其次,它只能包裝不超過一個參數的函數!盡管它在for_each中夠用了,但是你要是想用在超過一個參數的場合,那只有一句話:不可能的任務。

              是的,在標準C++中,這是不可能的任務。但事情并不總是悲觀的,至少有許多第三方庫提供了超越mem_fun的包裝。如boost::function等等。但是它也有限制:它所支持的參數仍然是有限的,只有十多個,盡管夠你用的了;同樣,它也是丑陋的,永遠不要想它能夠簡單的用&來搞定。

              也許,以失去美麗的代價,來換取質量上的保證,這也是C++對于函數指針的一種無奈吧……

              期待C++0x版本。它通過可變模板參數,能夠讓mem_fun的參數達到無限個……

            --------
               BTW: C++Builder擴展了一個關鍵字 closure ,允許成員函數指針如同普通函數指針一樣使用。也許C++0x能考慮一下……

            posted @ 2006-03-14 16:42 Beginning to 編程 閱讀(348) | 評論 (0)編輯 收藏

            一些基本的GDI操作BITMAP的方法 /zhuan

                 摘要: 1  2 #ifndef _BITMAP_H 3 #define _BITMAP_H 4  5 #include <windows.h> 6  7 void SaveImage(const char ...  閱讀全文

            posted @ 2006-03-10 11:27 Beginning to 編程 閱讀(1435) | 評論 (0)編輯 收藏

            僅列出標題
            共3頁: 1 2 3 

            導航

            統計

            常用鏈接

            留言簿(4)

            隨筆分類

            隨筆檔案

            文章檔案

            相冊

            BlogDev

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            欧美日韩精品久久久久| 久久综合狠狠色综合伊人| 久久精品国产一区| 久久久精品视频免费观看| 亚洲国产成人精品91久久久 | 国产成人精品久久| 久久久免费精品re6| 久久91综合国产91久久精品| 亚洲国产成人久久综合碰碰动漫3d| 国产亚州精品女人久久久久久 | 久久久国产精品| 久久WWW免费人成一看片| 国产精品视频久久久| 天天综合久久一二三区| 久久婷婷五月综合色高清| 94久久国产乱子伦精品免费| 偷偷做久久久久网站| 91精品国产综合久久久久久| 久久这里都是精品| 精品久久久久久无码中文野结衣| 亚洲狠狠婷婷综合久久蜜芽| 久久99精品久久久久久齐齐| 偷窥少妇久久久久久久久| 伊人色综合久久天天| 久久久久亚洲AV无码永不| 久久国产AVJUST麻豆| 国产精品久久久久一区二区三区| 精品国产乱码久久久久久1区2区| 国产精品久久久久久久久久影院 | 人人狠狠综合久久亚洲88| 2021久久精品免费观看| 久久只这里是精品66| 久久这里只精品99re66| 欧美粉嫩小泬久久久久久久| 亚洲欧美精品伊人久久| 久久国产精品-国产精品| 久久国产成人精品麻豆| 精品久久一区二区| 狠狠色丁香久久综合五月| 国产精品久久久久久搜索| 99久久er这里只有精品18|