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

            牽著老婆滿街逛

            嚴(yán)以律己,寬以待人. 三思而后行.
            GMail/GTalk: yanglinbo#google.com;
            MSN/Email: tx7do#yahoo.com.cn;
            QQ: 3 0 3 3 9 6 9 2 0 .

            linux下C++ 插件(plugin)實(shí)現(xiàn)技術(shù)

            文章來源:http://masterdog.bokee.com/563395.html
            ?
            ?????應(yīng)用程序中使用插件技術(shù),有利于日后的版本更新、維護(hù)(比如打補(bǔ)丁)和功能擴(kuò)展,是一種很實(shí)用的技術(shù)。其最大的特點(diǎn)是更新插件時(shí)無需重新編譯主程序,對(duì)于一個(gè)設(shè)計(jì)良好的應(yīng)用系統(tǒng)而言,甚至可以做到業(yè)務(wù)功能的在線升級(jí)。本文介紹了linux下用C++實(shí)現(xiàn)插件的一個(gè)簡(jiǎn)單實(shí)例,希望能對(duì)大家有所啟發(fā)。

            為了能做到更新插件時(shí)無需重新編譯主程序,要求主程序中定義的接口是定死的,而接口的實(shí)現(xiàn)被放到了具體的插件中,這樣主程序在運(yùn)行時(shí)刻將插件加載進(jìn)來,就可以使用這些接口所提供的功能了。在面向?qū)ο蟮南到y(tǒng)中,各個(gè)功能模塊被封裝到類中,因此在C++中實(shí)現(xiàn)插件技術(shù),就需要在主程序中提供基類,并為這些基類定義明確的接口,然后在插件(動(dòng)態(tài)庫或共享庫)中定義派生類,并實(shí)現(xiàn)基類中所有的接口。

            我們以計(jì)算多邊形面積為例,首先定義一個(gè)基類CPolygon:

            /* +******************************************************* */
            /* +******************************************************* */
            /* +******************************************************* */

            /* ?polygon.h? */

            #ifndef?__POLYGON_H__
            #define ?__POLYGON_H__

            #include?
            < ?iostream? >

            class ?CPolygon
            {
            public :

            ????CPolygon()
            {}

            ????
            virtual ? ~ CPolygon() {}

            ????
            virtual ? double ?area( void )? const ? = ? 0 ;
            }
            ;

            #endif ?/*?__POLYGON_H__?*/

            /* -******************************************************* */
            /* -******************************************************* */
            /* -******************************************************* */

            注意基類不一定是虛類(有純虛函數(shù)的類),但是接口一定要定義成虛函數(shù),因?yàn)樽罱K主程序是通過基類指針
            來調(diào)派生類的接口函數(shù),另外如果基類中有資源分配(new)的話,析構(gòu)函數(shù)一定要定義成虛的,否則不會(huì)被
            調(diào)用,造成內(nèi)存泄漏。

            接下來要定義派生類,并放到共享庫(triangle.so)中:

            /* +******************************************************* */
            /* +******************************************************* */
            /* +******************************************************* */

            /* ?triangle.h? */

            #ifndef?__TRIANGLE_H__
            #define ?__TRIANGLE_H__

            #include?
            " ?polygon.h? "
            #include?
            < ?iostream? >

            class ?CTriangle?:? public ?CPolygon
            {
            public :

            ????
            virtual ? double ?area( void )? const ;

            }
            ;

            #endif ?/*?__TRIANGLE_H__?*/


            /* ?triangle.cpp? */

            #include?
            " triangle.h "

            extern ? " C "
            {
            ????
            void ? * ?create()
            ????
            {
            ????????
            return ? new ?CTriangle;
            ????}


            }


            double ?CTriangle::area( void )? const
            {
            ????std::cout?
            << ? " area?of?triangle " ? << ?std::endl;
            ????
            return ? 0 ;
            }


            /* -******************************************************* */
            /* -******************************************************* */
            /* -******************************************************* */

            其中定義了函數(shù)“create”用來創(chuàng)建CTriangle類對(duì)象,該函數(shù)可讓主程序獲得CTriangle對(duì)象指針,從而
            可以訪問CTriangle類對(duì)象。主程序通過調(diào)用dlsym獲取指向該函數(shù)的指針,需要指出的是,由于dlsym被
            設(shè)計(jì)成c-style方式,因此調(diào)用c++定義的函數(shù)時(shí),需要加上extern "C"

            那么主程序是如何調(diào)用共享庫的呢,代碼片段如下:

            /* +******************************************************* */
            /* +******************************************************* */
            /* +******************************************************* */

            typedef?CPolygon
            * ?create_t();

            void ? * ?handle? = ?dlopen( " triangle.so " ,?RTLD_LAZY);

            if (? ! handle?)
            {
            ?std::cerr?
            << ?dlerror()? << ?std::endl;
            ?exit(
            1 );
            }


            create_t?
            * ?create_triangle? = ?(create_t? * )dlsym(handle,? " create " );

            CPolygon?
            * ?pObj? = ?create_triangle();

            if (? 0 ? != ?pObj?)
            {
            ?pObj
            -> area();
            }


            delete?pObj;

            dlclose(handle);

            /* -******************************************************* */
            /* -******************************************************* */
            /* -******************************************************* */

            主程序通過dlopen打開triangle.so,然后通過dlsym得到庫中的函數(shù)create指針,調(diào)用create后返回了
            指向CTriangle類對(duì)象的指針,類型是CPolygon的,由于虛函數(shù)的多態(tài)性, pObj->area() 實(shí)際是調(diào)用
            了CTriangle::area.

            好了,插件技術(shù)就是這么簡(jiǎn)單,回顧一下實(shí)現(xiàn)過程:寫一個(gè)基類,定義接口函數(shù),然后在共享庫中寫
            派生類,最后在主程序運(yùn)行時(shí)刻打開共享庫(dlopen),并通過create函數(shù)得到指向新創(chuàng)建的派生類
            對(duì)象的指針,然后利用虛函數(shù)的多態(tài)性,調(diào)用派生類的各種方法。


            不過進(jìn)一步使用后你可能會(huì)發(fā)現(xiàn),這樣實(shí)現(xiàn)會(huì)有些問題:

            1. 每寫一個(gè)派生類就需要重寫一個(gè)create函數(shù)

            注意到CTriangle類實(shí)現(xiàn)時(shí)定義的create函數(shù)必須返回 new CTriangle:

            ?

            extern ? " C "
            {
            ????
            void ? * ?create()
            ????
            {
            ????????
            return ? new ?CTriangle;
            ????}


            }

            ?

            那么如果再建一個(gè)類比如CRectangle, create函數(shù)必須重寫,返回 new CRectangle

            這樣做一方面麻煩,另外CTriangle、CRectangle兩個(gè)類不能放到同一個(gè)共享庫中,否則會(huì)編譯時(shí)刻
            提示重復(fù)定義錯(cuò)誤。


            2. 主程序無法判斷create函數(shù)返回的是哪個(gè)類所創(chuàng)建的對(duì)象

            當(dāng)只有一個(gè)基類(CPolygon)時(shí)主程序當(dāng)然知道返回的是CPolygon派生類的對(duì)象指針:
            create_t * create_triangle = (create_t *)dlsym(handle, "create");
            CPolygon * pObj = create_triangle();

            假如有多個(gè)基類,根據(jù)這些基類派生出不同類型的類時(shí),無法在主程序中判斷返回的是那個(gè)類的對(duì)象。


            3. 操作繁瑣

            沒有一個(gè)統(tǒng)一的操作界面,實(shí)現(xiàn)共享庫的加載、卸載、派生類對(duì)象的創(chuàng)建,特別是當(dāng)需要加載一個(gè)目錄
            下所有的共享庫時(shí),感覺一個(gè)一個(gè)地加載太麻煩了,能不能批量加載呢。


            通過動(dòng)態(tài)類加載和建立Helper類可以很好地解決上述問題,其中dynclass.h/dynclass.cpp中實(shí)現(xiàn)了動(dòng)態(tài)
            加載類對(duì)象,pluginhelper.h/pluginhelper.cpp實(shí)現(xiàn)了Plugin Helper,具體細(xì)節(jié)見附件。


            下面簡(jiǎn)單介紹一下使用步驟:


            1. 首先定義基類(CPolygon),方法同上

            2. 在共享庫中實(shí)現(xiàn)派生類

            比如CTriangle:

            /* +******************************************************* */
            /* +******************************************************* */
            /* +******************************************************* */

            /* ?triangle.h? */

            #ifndef?__TRIANGLE_H__
            #define ?__TRIANGLE_H__

            #include?
            " ?polygon.h? "
            #include??
            < ?iostream? >

            class ?CTriangle?:? public ?CPolygon
            {
            public :

            ????
            virtual ? double ?area( void )? const ;

            }
            ;

            #endif ?/*?__TRIANGLE_H__?*/


            /* ?triangle.cpp? */

            #include?
            " ?triangle.h? "
            #include?
            " ?dynclass.h? "

            DYN_DECLARE(CTriangle);

            double ?CTriangle::area( void )? const
            {
            ????std::cout?
            << ? " area?of?triangle " ? << ?std::endl;
            ????
            return ? 0 ;
            }


            /* -******************************************************* */
            /* -******************************************************* */
            /* -******************************************************* */


            注意到此時(shí)派生類的實(shí)現(xiàn)(triangle.cpp)中已沒有了那個(gè)討厭的create了,被我偷偷放到
            dynclass.cpp中了:

            extern ? " C "
            {
            ????
            void ? * ?createByClassName( const ? char ? * ?strClassName)
            ????
            {
            ????????
            return ?DYN_CREATE(strClassName);
            ????}

            }


            由于對(duì)任何派生類而言,該函數(shù)的實(shí)現(xiàn)都一樣,因此只需要實(shí)現(xiàn)一次,對(duì)使用者是不可見的,達(dá)到
            了從派生類中拿走的目的。

            另外增加了一個(gè)宏:DYN_DECLARE(CTriangle); 參數(shù)是類名(這里用到了RTTI),每個(gè)派生類對(duì)應(yīng)
            一個(gè)這樣的宏,該類就可以支持類對(duì)象的動(dòng)態(tài)加載了,需要包含頭文件dynclass.h


            2. 在主程序中如何使用

            使用起來也非常簡(jiǎn)單,在主程序(main.cpp)中:

            /* +******************************************************* */
            /* +******************************************************* */
            /* +******************************************************* */


            #include?
            " ?pluginhelper.h? "
            #include?
            " ?polygon.h? "



            CPluginHelper?pluginHelper;

            pluginHelper.Load(?
            " ./plugin " ,? " *.so " ?);

            CPolygon?
            * ?pbase? = ?(CPolygon? * )pluginHelper.Create( " CTriangle " );

            if (? 0 ? != ?pbase?)
            {
            ????pbase
            -> area();
            }


            delete?pbase;

            pluginHelper.Unload(?
            " ./plugin " ,? " *.so " ?);

            /* -******************************************************* */
            /* -******************************************************* */
            /* -******************************************************* */

            首先定義CPluginHelper對(duì)象,調(diào)用Load方法加載共享庫,其中第一個(gè)參數(shù)是共享庫的路徑,第二
            個(gè)參數(shù)是共享庫的名稱,共享庫名支持模式匹配,這里表示要加載./plugin目錄所有so共享庫,
            當(dāng)然也可以是某個(gè)具體的共享庫名。

            隨后可以通過CPluginHelper::Create方法,根據(jù)類名稱創(chuàng)建該類的對(duì)象,實(shí)現(xiàn)了參數(shù)化創(chuàng)建對(duì)象
            的目的,然后就是對(duì)該對(duì)象的調(diào)用,當(dāng)不用該對(duì)象時(shí),需要調(diào)用delete來刪除。

            最后,調(diào)用CPluginHelper::Unload將指定共享庫卸載。

            http://masterdog.bokee.com/inc/20050116132524159116.zip

            posted on 2006-08-26 04:37 楊粼波 閱讀(823) 評(píng)論(0)  編輯 收藏 引用 所屬分類: C++

            久久综合九色综合久99| 99精品久久精品一区二区| 国内精品久久久久久久影视麻豆| 青青热久久综合网伊人| 亚洲欧美日韩精品久久| 久久国产精品免费一区| 久久久精品久久久久久| 亚洲国产视频久久| 伊人久久综合精品无码AV专区 | 国产高潮久久免费观看| 久久国产成人亚洲精品影院| 久久国产美女免费观看精品 | 国内精品人妻无码久久久影院导航 | 偷偷做久久久久网站| 中文字幕久久精品无码| 久久99国产精品99久久| 精品国产热久久久福利| 超级碰碰碰碰97久久久久| 久久精品a亚洲国产v高清不卡| 日韩一区二区久久久久久| 日韩影院久久| 精品国际久久久久999波多野| 国产精品综合久久第一页 | 久久久精品一区二区三区| 久久亚洲AV无码西西人体| 亚洲精品无码久久久久久| 久久精品国产99国产精品澳门 | 2021国内久久精品| 成人妇女免费播放久久久| 久久99精品久久久久久野外| 久久国产色av免费看| 久久久久综合网久久| 国产精品久久新婚兰兰| 久久99国产精品久久99果冻传媒| 久久男人AV资源网站| 国产精品久久久久jk制服| 午夜精品久久久久久影视777| 久久精品www人人爽人人| 色综合久久久久综合99| 久久99热精品| 色综合久久无码五十路人妻|