• <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>

            martin

            thinking

            常用鏈接

            統計

            software

            最新評論

            #

            模板與泛型算法

            前段時間讀了一本書《C++沉思錄》,偶有感,摘錄如下:
            模板和泛型算法(摘自 《c++沉思錄》):
             
            一個特例:
            1.假設我們希望從整數數組中找到第一個等于某給定值的元素.編寫如下代碼:
            const int*
            find1(const int* array, int n, int x)
            {
                const int *p = array;
                for( int i = 0; i < n; i++)
                {
                    if(*p==x)
                        return p;
                    ++p;
                }
                return 0;
            }
             
            2.泛型化元素類型:
            用類型T來表示整型等,適當的時候可以把const也包含在T中,得到如下函數.
            template<class T>
            T* find2(T* array, int n, constT& x)
            {
                T* p = array;
                for(int i=0; i<n; i++)
                {
                    if(*p==x)
                        return p;
                    ++p;
                }
                return 0;
            }
               
            3.推遲計數.
            為了避免預先知道有多少個元素,我們改變函數,使它接受指向第一個元素和最后一個元素之后元素的指針
            template<class T>
            T* find3(T* array, T* beyond, constT& x)
            {
                T* p = array;
                while(p!=beyond)
                {
                    if(*p ==x)
                        return x;
                    ++p;
                }
                return 0;
            }
            用!=而不用<來判斷循環結束并不是偶然.從某種角度來說,兩者沒有區別,如果find3的輸入有意義,則p就小于beyond,直到它們相等為止.但是,由<加以總體排序的類型通常也能用!=來進行比較.另一方面,考慮一下我們以后可能會用到來代替指針的類型,他們可以很好地定義!=,但不一定能定義<.此時,使用<就是一個不合理的假設.
             
            另外,我們還假設了,0可以轉換成一個與其他所有的值不同的指針值.我們稍微做一點改變,以避免這種假設:如果程序中要找的值沒找到,它就返回beyond而不是0.
            template<class T>
            T* find4(T* array, T* beyond, constT& x)
            {
                T* p = array;
                while(p!=beyond)
                {
                    if(*p ==x)
                        return x;
                    ++p;
                }
                return beyond;
            }
             
            因為程序要么返回適當的T*, 要么返回beyond.故程序代碼可以被修改如下:
            template<class T>
            T* find5(T* array, T* beyond, constT& x)
            {
                T* p = array;
                while(p!=beyond && *p != x)
                    ++p;
                return p;
            }
             
            4.地址的獨立性
             到目前為止,我們還是依賴于傳遞來的指針,該指針要指向要查找的數據的開頭.但是如果仔細分析一下,會發現我們只依賴于指針的某些保留特性:
            1)可以把指針當參數接收,并把它們作為結果返回.
            2)可以比較指針是否相等.
            3)可以解除引用,以便得到值:*p.
            4)可以遞增,以指向下一個元素.
             
            只要符合上述條件的類型即可,不一定是指針類型.假設把T*作為模板參數,我們就取消了對指針的依賴:
            template<class P,class T>
            T* find6(P start, p beyond, constT& x)
            {
                while(start !=beyond && *start != x)
                    ++start;
                return start;
            }
             
            我們已經完全剔除了函數中關于具體類型的信息.根本沒有要求p是指針,只要求p滿足上述的四個特性.
             

             

            posted @ 2009-03-06 17:43 martin_yahoo 閱讀(1807) | 評論 (3)編輯 收藏

            C++同步鎖管理的一種方法

            在C++中,通過提供構造函數、析構函數來對處理資源的獲取、釋放。
            通過C++的這種機制,我們可以很方便地處理C++中的加鎖同步機制。把鎖對象作為Guard對象的一個成員(m_lock),然后在Guard對象的構造中對m_lock進行加鎖:m_lock.acquire(),在Guard對象的析構函數中進行解鎖:m_lock.release()。先給出代碼實例如下:

            template <class T>
            class Guard
            {
            public :
                    Guard(const T & lock);
                    virtual ~Guard();

            private:
                    const T & m_lock;
            };

            template <class T>
            Guard<T>::Guard(const T & lock) :
                    m_lock(lock)
            {
                    m_lock.acquire();
            }

            template <class T>
            Guard<T>::~Guard()
            {
                    m_lock.release();
            }

            我們可以在應用程序中這樣使用它:

             void testFunc(.....)

            {

              Guard<MutexWrapper>  guard(mutex);

              ...

            }

            在剛進入函數testFun(...),創建guard對象,并自動對mutex進行加鎖,對特定數據(resource)進行保護。當應用離開testFunc函數模塊時,根據guard對象的作用域和生命周期,此時guard對象的析構函數將被調用,因此將自動對mutex進行解鎖。在此之后應用的其他線程將可以訪問以前被mutex進行保護起來的資源。

             

            利用上面的方法,我們可以包對資源的同步訪問和訪問控制交給C++的編譯器,而不需要進行人工干預,從而減輕應用開發人員的工作負擔。

            posted @ 2009-03-04 18:11 martin_yahoo 閱讀(4152) | 評論 (8)編輯 收藏

            C++的一些基礎知識

            C++中類包含三種成員訪問說明符:public, private 和 protected.
            在程序能訪問類對象的任何地方都可以訪問任何在成員訪問說明符public后面聲明的數據成員和成員函數.成員訪問符private后面的數據成員和成員函數只能由該類的成員函數或友元訪問.基類的protected成員只能被基類的成員和友元已及派生類的成員和友元訪問.
            在C++中還存在三中繼承方式:public, private, protected.
             
            對于它們的論述可以在任意一本關于C++的書中都可以找到.大家對public繼承都比較熟悉.但我們偶爾也會看到private繼承.private繼承時基類中的public,private成員變成派生類中的private成員.基類中的private成員在派生類中隱藏.
             
            這里簡單介紹一下以下兩種情況的異同:
            (1)B private 繼承A
            (2)A是B的一個私有成員的異同.
             
            相同點:A的接口(public 成員函數)都只對B開放,不對外開放. 
            不同點:在(1)中A的public, protected成員都為B的private成員,B的成員函數可以直接訪問.在(2)中A的成員都不是B的成員,并且B不能訪問A的protected成員,要訪問A的public成員也要借助A的對象.
             
            下面再講一些編譯器在構造類時所采取的缺省操作:
            1.如果類沒有聲明構造函數,編譯器會聲明一個默認構造函數.
            2.如果沒有聲明拷貝構造函數,編譯器會隱式地生成一個.
            3.如果沒有聲明賦值操作符,編譯器會隱式地生成一個.
            4.如果沒有聲明析構函數,編譯器會隱式地生成一個.
             
            隱式生成的函數都是public的.
            如果接受一個副本是有效的行為,就該聲明并定義拷貝構造函數和賦值操作符.如果接受一個副本是禁止的,你可以將拷貝構造函數和賦值操作符聲明為private,并且不實現它們,這樣可以阻止編譯器生成缺省的操作,從而防止客戶復制類對象.
             
            下面是代碼實例:
             
            class test{
             
            };
             該類中不包含任何成員,也沒聲明任何方法.編譯器會缺省生成下列方法:
            test::test()
            {
            }
             
            test::~test()
            {
            }
             
            test::test(const test& rt)
            {
             ...
            }
             
            test& test::operator=(const test& rt)
            {
            ...
            }
             
            這些方法都是public的.
             
            如果想阻止編譯器生成缺省的拷貝構造函數,和賦值操作,可以進行如下操作:
            class test{
             
            private:
                test(test& rt);                        //    該方法被定義為private,并且不被實現.
                test& operator=(test& rt);        //    該方法被定義為private,并且不被實現.
            };
             

            posted @ 2009-03-04 14:51 martin_yahoo 閱讀(1406) | 評論 (2)編輯 收藏

            程序中的跟蹤方法

            在應用開發構成中,我們經常在程序中加入一些打印語句,來對程序的執行流進行跟蹤.在C或C++中可以利用下列語句來實現:
            (1)
            printf("enter %s\n",(char *)funcName);
            cout<<"enter "<< s_funcName << endl;
             
            但這樣處理有點不足,就是該語句只輸出到標準輸出上,我有時希望這些輸出被定向到特定文件,輸出成日志.為此,我們可以把這些函數進行包裝,把輸出流ostream(標準輸出或文件輸出)作為包裝函數的一個參數:
            (2)
            printWrap(ostream out,format, args);
            注:此處的args, format表示要輸出的參數和相應的參數格式.
            當然我們還可以對它進行進一步的改進:在該函數中,加入預定以的符號常量__LINE__(當前源代碼行的行號,為整數常量),__FILE__(假定的源文件名,某個字符串).這樣我們可以知道程序運行到了那個源文件,并且那一行.
             
            現在(2)中的處理方式比(1)中處理方式已經有明顯的改善了.
            但這種方式還稍微有點不足.當我們想要跟蹤一個函數的執行,即知到執行流進入某函數,何時離開某函數時,這種處理方式有點不足.每個函數都有一個入口,但可能有多個出口,這樣就需要在每個入口和出口處加上printWrap(ostream out,args)語句,并且在C++中,當執行流遇到異常退出該函數時,可能有些printWrap語句并沒有被執行,從而沒有輸出記錄.
             
            為此,我們可以對(2)進行進一步改進.我們可以設計一個類,在該類對象的構造函數,析構函數中進行輸出.在函數的入口處,調用對象的構造函數進行輸出;在函數的出口處,或異常退出時,調用對象的析構函數進行輸出.
            我們可以把該類簡單總結如下:
            (3)
            class Trace{
                public:
                            Trace(int iDebugLevel,ostream out, format,args) { cout <<"Hello\n";}
                            ~Trace() { cout << " Goodby\n";}
                               int getDebugLevel();
                private:
                        ...
                         int    iDebugLevel;
                         ostream m_out;
            };
             
            注:  我們可以用printWrap(..)替換cout << ....。printWrap中的輸出流在Trace的構造函數中傳到Trace實例中,并被保存。
             
            我們還可以對它進行一點改進,以提高它的性能。因為采用上面的對象。則每次都會進行輸出或進行日志記錄.我們可以通過構造函數在Trace的實例中,設置一個iDebugLevel變量和ostream。并在系統中設置一個統一的debugLevel.在每次進行輸出時進行iDebugLevel, debugLevel比較,如果iDebugLevel <= debugLevel, 則進行輸出,否則則不進行輸出.
             

            posted @ 2009-03-03 16:39 martin_yahoo 閱讀(1328) | 評論 (0)編輯 收藏

            C/C++混合編程

            前段時間,碰到了C,C++混合編程的需求,經過努力,順利解決問題.現把這方面的知識做一下簡單的總結:
             
            1.當C++文件要用到C語言中的函數代碼時,采用下屬方法即可:
            在C++中的.h文件或.cpp文件中加入下列代碼,
            #define LINT_ARGS 1
            extern "C" {
            #include "system.h"
            }
             
            然后在代碼中直接調用這些函數即可.

            注解:
            1.1 LINT_ARGS 1表示在檢查C語言中的函數原型時,要對函數原型的參數進行檢查. 
            1.2. "{ }" 中包含的頭文件為C語言中的頭文件.
            1.3.extern "C" 告訴鏈接器,這些頭文件中的函數被當做C語言中的函數來處理.
             
            下面以一個實例加以說明:
            下面為一個C語言的頭文件(sysgct.h):
            #ifdef LINT_ARGS
              int  GCT_send(unsigned int task_id, HDR *h);
              ......
            #else
              int  GCT_send();
              ......
            #endif
            ~
            in file MapBaseReq.cpp 文件中
            #include ....
            extern "C"
            {
            #include "sysgct.h"
            }
            void
            MapBaseReq::sendPdu(const BasePdu_var& thePduP)
            {
                ...
                if (GCT_send(m->hdr.dst, (HDR *)m) != 0)
                    {
                            relm((HDR *)m);
                            SETERR1(errSWErrorMsg, "sendPdu(): GCT_send() Failed");
                    }
               ...
            }
             
            2.當C文件要用到C++語言某個類中的方法時,可以采用下列方法:
            2.1 在cpp文件中用下列方式定義函數:
            extern "C" returnType FunName(parameters list).
             
            2.2 然后在相應的頭文件中進行聲明:
            extern returnType FunName(parameters list);
             
            2.3 在相應的.c文件中包含該頭文件,然后直接利用相應的函數即可.
             
            下面給出實例.
             
            2.4 cpp文件

            #include <iostream>
            #include <iomanip>
            #include "TTDebug.h"
            using namespace std;

            extern "C"
            {
            #include "Utility.h"
            }

            static int display_hex_buffer(unsigned char* buffer, unsigned char* ptr,int len);

            extern "C" void tDebug_traceFunc(int level, char* trace)
            {
                    TDEBUG_TRACEFUNC(level,trace);
            }

            extern "C" void nDebug(int level, unsigned char* args, int iLen, int cid)
            {
                    unsigned char buf[512];
                    if(0 != TTDebug::instance() && TTDebug::instance()->isTTDebugOn(level))
                    {
                            /* Check whether the current thread already holds the mutex lock */
                            LockGuard<MutexWrapper> guard(TTDebug::instance()->mutex());
                            TTDebug::instance()->traceStart(level, __FILE__, __LINE__);
                            memset(buf,0,512);
                            display_hex_buffer(buf,args,iLen);
                            TTDebug::instance()->outStream() << "Send Msg(0-0x" << setw(4) << setfill('0') << hex << cid <<"):0x" << buf;
                            TTDebug::instance()->traceEnd();
                    }
            }

            2.5 .h 文件

            #ifndef __UTILITY_H
            #define __UTILITY_H

            extern void tDebug_traceFunc(int level, char* trace);
            extern void nDebug(int level, unsigned char* args,int iLen, int cid);

            #endif
             
            2.6 cpp文件中定義的函數在c文件中調用實例
            在test.c文件中:

            ...

            int ctu_ent(msg,pInt)
              MSG* msg;
              int *pInt;
            {

             tDebug_traceFunc(10,"ctu ctu_ent");

              HDR *h;
              MSG *m;

               ...

            }

            ...


            posted @ 2009-03-03 16:25 martin_yahoo 閱讀(4815) | 評論 (3)編輯 收藏

            利用C++開發架構程序的方法

            在運用JAVA,C++等面向對象的語言進行開發的時候,不可避免地要用到繼承.即從一個父類(P)派生出相應的子類(C).在開發應用的時候,我們可以僅從單個類的角度來考慮繼承或派生.但是我們可以進一步對它進行引申.比如我們可以用基類(或純抽象類,JAVA中的接口)來開發處理某類業務的抽象架構或平臺,然后針對具體的應用,我們派生出相應的派生類,讓它們來完成具體業務的具體邏輯.
            在C++中,基礎架購用基類寫就,但具體業務邏輯用派生類來實現.為了做到這一點,我們必須在架構中指向基類對象的指針(->操作符),并且定義相應的虛函數(或純虛函數).這樣實現程序的動態多態.這樣實現既滿足了面向對象設計的OCP原則(open-close principle).
             
            在基礎架構中可能還包含保存基類指針的容器,這些指針可能后來所賦之值是派生類的指針,并且考慮到對象的生命周期,這些對象應該是通過NEW操作在heap上生成的對象,而不是在stack上保存的局部對象.為了保證這些對象的自動銷毀,不需要應用開發人員的人工干預,這些保存在容器中的指針最好是含有基類指針的智能指針SmartPointer,或者說是代理類.SmartPointer是代理類中的一種.
             
            根據前一篇文章的分析,在應用對對象指針的處理,采用了智能指針.但指向基類(P)的智能指針(SmartPp)與指向子類(C)的智能指針(SmartPc)不是父類與子類的關系,它們應該是同一類的不同實例.因此還應該對智能類定義如下操作,使之滿足轉型要求:
            (1)從智能指針中獲取指向對象指針的能力.
            (2)根據指向對象的指針生成智能指針的能力.
            滿足這兩點,我們就可以從SmartPc中獲取pC(指向子類的指針),然后把它轉型成pP(指向父類的指針),然后再根據pP生成SmartPp,然后保存在基礎架構的容器中.在實際應用的過程中,會用到指向父類的指針,但此時它實際上是指向子類的指針,在程序運行的過程中,將用到動態多態性,即虛函數來處理相應的應用.
             
            BTW(順便說一下),因為一般說來容器(MAP,vecotr,或數組)只能保存一種類型,另外又要用到運行時的多態,最好保存指向基類對象的指針,而不直接保存對象,否則子對象將被切割,只保留父類部分,其余將被丟棄.另外為減少對對象管理的負擔,最好在容器中保存對象的代理對象.

            posted @ 2009-03-03 15:10 martin_yahoo 閱讀(1462) | 評論 (0)編輯 收藏

            C++中的智能指針

            1.淺論C++中的智能指針(Smart Pointer)
            簡單地講,智能指針是用一個對象來對指針進行建模,使之具有指針的特性,跟指針具有相同含義的->,*操作.并且通過對象的構造函數(獲取資源),析構資源(釋放資源)來對資源進行管理,從而減少程序員對通過new操作獲取到的對象的生命周期進行管理的負擔.
            根據《Moden C++ Design》, 我們可以構造具有很多正交特性的智能指針。
            1.1  C++中的智能指針與JAVA中的對象
            前段時間跟朋友聊了些有關JAVA的東西,感覺上Java中的對象就是C++中的智能指針,但具有不同的資源釋放方式。在JAVA中,不能象C++中運用" A a;"語句聲明得到一個類(A)的事例a,而必須通過下列語句來獲得:Aa = new A.要在釋放a時,應用必需通知
            GC(垃圾收集功能)來釋放該實例所占用的資源。當然,JAVA中的對象有一小點同C++中的職能智能不同,因為在C++中指針不具有"."操作符,故智能指針一般也不提供"."操作符,但在Java中都是通過"."操作符對對象進行操作的,不過我們可以把C++中職能指針的"->"操作符與
            Java中的"."操作符進行類比。
            1.2  引用計數型智能指針
            在C++中有一種常用的智能指針是引用計數型智能指針:RCSmartPtr. 它的實現基理如下:
            首先,存在RCObject,即存在一個對象,該對象提供引用計數接口。
            另外,要存在指向RCObject的RCSmartPtr對象,在RCSmartPtr對象的構造過程中,把指向RCObject的指針作為參數傳入RCSmartPtr中。因此每增加一個RCSmartPtr對象,就多了一個指向RCObject的指針。RCSmartPtr可以通過調用RCObject的引用計數接口,增加RCObject
            的引用計數。同樣的道理可以在RCSmartPtr對象的析構函數中調用RCObject的引用記數接口來減少RCObject的引用記數。
            第三,在對RCObject的引用計數進行操作時對引用計數進行檢查,如果引用計數為0,則RCObject將摧毀本身,從而釋放該對象所占用的資源。
            通過這種方式,我們就可以把對資源的管理交給機器來管理,解除了對人工的倚賴。
             

            posted @ 2009-03-03 15:00 martin_yahoo 閱讀(4183) | 評論 (5)編輯 收藏

            僅列出標題
            共2頁: 1 2 
            久久久久se色偷偷亚洲精品av| 九九久久精品国产| 无码人妻少妇久久中文字幕蜜桃 | 久久久这里只有精品加勒比| 香蕉久久夜色精品国产尤物| 亚洲国产精品无码久久久秋霞2| 97久久精品午夜一区二区| 久久99久久无码毛片一区二区| 久久久久久伊人高潮影院| 亚洲国产精久久久久久久| 亚洲&#228;v永久无码精品天堂久久| 国产免费久久精品99re丫y| 99国产欧美精品久久久蜜芽| 一级a性色生活片久久无| 美女写真久久影院| 男女久久久国产一区二区三区| 久久av高潮av无码av喷吹| 久久男人Av资源网站无码软件 | 亚洲乱码精品久久久久..| 久久99精品国产麻豆蜜芽| 亚洲AV无码久久寂寞少妇| 亚洲精品视频久久久| 伊人丁香狠狠色综合久久| 久久夜色精品国产噜噜噜亚洲AV| 久久精品国产精品亚洲人人| 久久99精品国产自在现线小黄鸭| 97精品伊人久久大香线蕉| 国内精品久久久久久久影视麻豆| 久久人人爽爽爽人久久久| 久久精品成人欧美大片| 久久久久久噜噜精品免费直播| 青青草国产精品久久久久| 97精品伊人久久久大香线蕉| www.久久热.com| 久久国产亚洲精品麻豆| 97久久国产亚洲精品超碰热| 久久亚洲精品中文字幕| 久久精品国产亚洲av水果派 | 久久国产乱子伦精品免费强| av午夜福利一片免费看久久| 亚洲欧美成人综合久久久|