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

            Michael's Space

            Technology changes the world, serves the people.

            COM的由來

            Posted on 2006-07-04 17:59 奔跑的阿甘 閱讀(506) 評論(0)  編輯 收藏 引用 所屬分類: COM/ATL
            COM的由來
            Michael 2006年07月04日

            最近,公司的產(chǎn)品在支持SNA網(wǎng)絡時出現(xiàn)了一個怪異的問題,終端和主機連接總是無法建立,經(jīng)過追查源碼發(fā)現(xiàn)應用客戶端在調(diào)用SNA網(wǎng)絡服務庫的接口時莫名其妙的改變了網(wǎng)絡服務對象的數(shù)據(jù)成員,實際上,該數(shù)據(jù)成員只有在對象構造函數(shù)中被初始化過一次,其他地方?jīng)]有任何寫操作。
            根據(jù)應用客戶端對多網(wǎng)絡協(xié)議的支持代碼,我做了以下測試,Client應用調(diào)用一個Operate接口,由兩個不同的服務端實現(xiàn):

            Client包含IOperator接口文件,調(diào)用operate方法:
            1?class?EXPORIMP?IOperator?{
            ?2?public:
            ?3?????IOperator();
            ?4?????~IOperator();
            ?5?????
            ?6?????long?operate(const?long?var1,?const?long?var2);
            ?7?????
            ?8?private:
            ?9?????int?a;
            10?????int?b;
            11?};

            operate的第一個實現(xiàn):server1.dll
            ?
            1class?EXPORIMP?IOperator?{
            2??public:
            3???????IOperator();
            4???????~IOperator();
            5???????
            6???????long?operate(const?long?var1,?const?long?var2);
            7???????
            8???private:
            9??????int?a;
            10??????int?b;
            11??};

            operate的第二個實現(xiàn):增強的server1.dll
            ?1class?EXPORIMP?IOperator?{
            ?2?public:
            ?3?????IOperator(); // Initialize szName, a, b
            ?4?????~IOperator();
            ?5?????
            ?6?????long?operate(const?long?var1,?const?long?var2); //access szName
            ?7?????
            ?8?private:
            ?9?????char?szName[256];
            10?????int?a;
            11?????int?b;
            12?};

            client通過server1.lib來實現(xiàn)接口調(diào)用,server1的發(fā)布者在發(fā)布dll后發(fā)現(xiàn)server1中存在某個BUG,或者為了改進operate的效率,因而引入了szName成員并更新了operate接口實現(xiàn),然后重新發(fā)布了增強版的server1 DLL。客戶拿到新版本后很高興,但是,當他興致勃勃地替換掉老的DLL時,發(fā)現(xiàn)自己的客戶端再也跑不起來了,令人厭煩的異常!
            我們發(fā)現(xiàn)兩種實現(xiàn)的唯一區(qū)別是私有數(shù)據(jù)成員的組成,但是DLL的PUBLIC接口沒有變化為什么會出現(xiàn)異常呢?
            原來,客戶端在第一次編譯時引入老的server1.lib,并沒有準備為新的dll分配256個char變量,但是客戶端調(diào)用的新的dll接口時卻對不屬于自己的內(nèi)存塊做了操作,其實,客戶端在創(chuàng)建IOperator對象時就出錯了!
            我們稱以上的接口定義為“老”的接口定義方式,這種方式下,如果改變了數(shù)據(jù)成員而且公用接口對數(shù)據(jù)成員又做了操作,那么在不重新編譯客戶程序的情況下,客戶程序?qū)⒑翢o疑問的出現(xiàn)異常甚至崩潰。

            封裝-C++的三大特性之一,在這里迷惑了我們的視眼。因為利用PRIVATE和PUBLIC關鍵字定義的封裝是“語法”上的封裝,也就是說,在同一工程內(nèi)是不能夠直接訪問PRIVATE的成員的,否則編譯器會報告語法錯誤,實際上,編譯器在編譯重用庫的時候還是需要訪問重用類的所有成員(包括PRIVATE),以便在客戶中構造類對象。這樣,“接口”和“實現(xiàn)”實際上是一個東西。
            “接口”和“實現(xiàn)”的真正分離,要求C++的“封裝”是種“二進制層次”的封裝。也就是說,不管重用類的實現(xiàn)如何改變,它提供的接口對于客戶來說都是靜止的。因此,我們把接口類和實現(xiàn)類分離的時候,要讓接口類的二進制布局不會隨著實現(xiàn)類的變化而變化。
            下述對接口類和實現(xiàn)類的分離是成功的,因為不論實現(xiàn)類如何改進,接口IOperatorItf的內(nèi)存布局從未改變。但是,一個殘酷的問題是,IOperatorItf類必須聲明IOperator的所有擁有的接口,對于一個稍微大型的類來說,這是個煩瑣的過程,而且,嵌套調(diào)用的開銷也不可忽略。
            ?1?class?EXPORIMP?IOperatorItf?{?? //接口類
            ?2?class?IOperator;
            ?3?IOperator*?m_pThis;
            ?4??public:
            ?5???????IOperator();
            ?6???????~IOperator();
            ?7???????
            ?8???????long?operate(const?long?var1,?const?long?var2);
            ?9??};
            10?
            11?class?EXPORIMP?IOperator?{?? //實現(xiàn)類
            12??public:
            13???????IOperator();
            14???????~IOperator();
            15???????
            16???????long?operate(const?long?var1,?const?long?var2);
            17???????
            18???private:
            19??????int?a;
            20??????int?b;
            21??};

            這里還有個非常關鍵的問題,上述改進并沒有解決編譯器/鏈接器的標識符名字改編問題,這造成嚴重的編譯器/鏈接器依賴。
            編譯器之間不可避免的在編譯細節(jié)上存在多種差異,然而,有一條特性卻是所有的編譯器都滿足的:“某個給定平臺上的所有C++編譯器都實現(xiàn)了同樣的虛函數(shù)調(diào)用機制”,即對于每個編譯器,類的對象在內(nèi)存中如何表示,以及在運行時虛函數(shù)如何被動態(tài)調(diào)用,都是一樣的。這個特性非常漂亮的解決上述問題。

            ?1?//接口類
            ?2?class?IOperatorItf?{
            ?3??public:
            ?4???????vritual?long?operate(const?long?var1,?const?long?var2)=0;
            ?5??};
            ?6?extern?"C"?IOperatorItf*?CreateOperatorInstance();
            ?7?
            ?8?//實現(xiàn)類
            ?9?class?IOperator?:?public?IOperatorItf?{
            10??public:
            11???????IOperator() {a=b=1};
            12???????~IOperator();
            13???????
            14???????long?operate(const?long?var1,?const?long?var2) {return (a+b)};
            15???????
            16???private:
            17??????int?a;
            18??????int?b;
            19??};
            20?extern?"C"?IOperatorItf*?CreateOperatorInstance() { return (new IOperator)};

            這里,接口類和實現(xiàn)類在定義上是獨立的,但是因為繼承,實現(xiàn)類的內(nèi)存布局是接口類布局的二進制超集,這種“二進制層次”的繼承解決了我們前面幾種方案的所有問題。

            “接口”和“實現(xiàn)”的分離是重用組件的核心,當我們學會用虛函數(shù)表來表達我們的接口時,COM已經(jīng)在向我們招手了。

            [完]
            久久久久久极精品久久久| 国产婷婷成人久久Av免费高清| 人人狠狠综合久久亚洲婷婷| 99久久精品免费国产大片| 亚洲午夜精品久久久久久浪潮| 天天爽天天狠久久久综合麻豆| 日本久久久久久中文字幕| 一本久久综合亚洲鲁鲁五月天亚洲欧美一区二区 | 久久久久国产精品嫩草影院| 亚洲AV成人无码久久精品老人| 狠狠干狠狠久久| 久久久久久久精品成人热色戒| 大香网伊人久久综合网2020| 日产精品久久久久久久| 久久综合九色综合97_久久久| 国产成人综合久久精品红| AA级片免费看视频久久| 亚洲午夜久久久影院| 亚洲欧洲精品成人久久奇米网| av无码久久久久不卡免费网站 | 久久99国产精品成人欧美| 久久精品无码专区免费东京热| 久久精品国产WWW456C0M| 99久久精品国产麻豆| 亚洲精品乱码久久久久久蜜桃不卡| 久久无码一区二区三区少妇 | 人妻无码精品久久亚瑟影视| 精品久久久久久久久久中文字幕 | 久久久久亚洲AV无码专区体验| 久久WWW免费人成—看片| 国产∨亚洲V天堂无码久久久| 漂亮人妻被黑人久久精品| 亚洲国产另类久久久精品小说| 亚洲精品国产综合久久一线| 久久se精品一区二区影院| 国产香蕉97碰碰久久人人| 色综合久久综合网观看| 国产99久久久国产精免费| 99久久www免费人成精品| 狠狠色丁香婷婷综合久久来来去| 久久久精品一区二区三区|