青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

posts - 319, comments - 22, trackbacks - 0, articles - 11
  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

DLL導出類的問題

Posted on 2011-08-10 07:23 RTY 閱讀(843) 評論(0)  編輯 收藏 引用 所屬分類: C/C++Windows
DLL導出類的問題

http://www.diybl.com/course/3_program/c++/cppjs/200833/102641.html
DLL動態鏈接庫是程序復用的重要方式,DLL可以導出函數,使函數被多個程序復用,DLL中的函數實現可以被修改而無需重新編譯和連接使用該DLL的應用程序。作為一名面向對象的程序員,希望DLL可以導出類,以便在類的層次上實現復用。所幸的是,DLL確實也可以導出類。

然而事實卻沒這么簡單,導出類的DLL在維護和修改時有很多地方必需很小心,增加成員變量、修改導出類的基類等操作都可能導致意想不到的后果,也許
用戶更新了最新版本的DLL庫后,應用程序就再也不能工作了。這就是著名的DLL Hell(DLL地獄)問題。

DLL地獄問題是怎么產生的呢?看下面的例子,假設DLL有一個導出類ClassD1:
class ClassD
{
       public:
int GetInt();
              private:
int m_i;
};
int ClassD::GetInt()
{
       return m_i;
}

應用程序使用現在的代碼來使用這個類:
ClassD d;
printf(“%d”, d.GetInt());
 
程序進行正正常,沒有什么問題。后來DLL需要升級,對ClassD進行了修改,增加了一個成員變量,如下:
class ClassD // 修改后
{
       public:
int GetInt();
              private:
                     int m_i2;
int m_i;
};

把新的DLL編譯連接完成后,復制到應用程序目錄,這個倒楣的應用程序調用GetInt方法恐怕再也無法得正確的值了。事實上它還算幸運的,如果GetInt的實現改成如下這樣,那么它馬上就要出錯退出了。
int ClassD::GetInt() // 修改后
{
       return m_i++;
}

這樣的事情,稱它是個地獄(Hell)一點也不夸張。為什么會出錯呢?我們要先從類實例的創建開始,看看使用一個類的工作過程。

首先,程序語句“ClassD d;”為這個類申請一塊內存。這塊內存保存該類的所有成員變量,以及虛函數表。內存的大小由類的聲明決定,在應用程序編譯時就已經確定。

然后,當調用“d.GetInt()”時,把申請的這一塊內存做為this指針傳給GetInt函數,GetInt函數從this指向的位置開始,加上m_i應有的偏移量,計算m_i所在的內存位置,并從該位置取數據返回。m_i相對this的偏移量是由m_i在類中定義的位置決定的,定義在前的成員變量在內存中也更靠前。這個偏移量在DLL編譯時確定。

當ClassD的定義改為修改后的狀態時,有些東西變了。

第一個變的是內存的大小。因為修改后的ClassD多了一個成員變量,所以內存也變大了。然而這一點應用程序并不知道。

第二個變的是m_i的偏移地址。因為在m_i之前定義了一個m_i2,m_i的實現偏移地址實際已經靠后了。所以d.GetInt()訪問的將是原來m_i后面的那個位置,而這個位置已經超出原來那塊內存的后部范圍了。

很顯然,在更換了DLL后,應用程序還按原來的大小申請了一塊內存,而它調用的方法卻訪問了比這塊內存更大的區域,出錯再在所難免。

同樣的情形還會發生在以下這些種情況中:

1) 應用程序直接訪問類的公有變量,而該公有變量在新DLL中定義的位置發生了變化;
2) 應用程序調用類的一個虛函數,而新的類中,該虛函數的前面又增加了一個虛函數;
3) 新類的后面增加了成員變量,并且新類的成員函數將訪問、修改這些變量;
4) 修改了新類的基類,基類的大小發生了變化;

等等,總言而之,一不小心,你的程序就會掉進地獄。通過對這些引起出錯的情況進行分析,會發現其實只有三點變化會引起出錯,因為這三點是使用這個DLL的應用程序在編譯時就需要確定的內容,它們分別是:
1) 類的大小;
2) 類成員的偏移地址;
3) 虛函數的順序。

要想做一個可升級的DLL,必需避免以上三個問題。所以以下三點用來使DLL遠離地獄。

1,不直接生成類的實例。對于類的大小,當我們定義一個類的實例,或使用new語句生成一個實例時,內存的大小是在編譯時決定的。要使應用程序不依賴于類的大小,只有一個辦法:應用程序不生成類的實例,使用DLL中的函數來生成。把導出類的構造函數定義為私有的(privated),在導出類中提供靜態(static)成員函數(如NewInstance())用來生成類的實例。因為NewInstance()函數在新的DLL中會被重新編譯,所以總能返回大小正確的實例內存。

2,不直接訪問成員變量。應用程序直接訪問類的成員變量時會用到該變量的偏移地址。所以避免偏移地址依賴的辦法就是不要直接訪問成員變量。把所有的成員變量的訪問控制都定義為保護型(protected)以上的級別,并為需要訪問的成員變量定義Get或Set方法。Get或Set方法在編譯新DLL時會被重新編譯,所以總能訪問到正確的變量位置。

3,忘了虛函數吧,就算有也不要讓應用程序直接訪問它。因為類的構造函數已經是私有(privated)的了,所以應用程序也不會去繼承這個類,也不會實現自己的多態。如果導出類的父類中有虛函數,或設計需要(如類工場之類的框架),一定要把這些函數聲明為保護的(protected)以上的級別,并為應用程序重新設計調用該慮函數的成員函數。這一點也類似于對成員變量的處理。

如果導出的類能遵循以上三點,那么以后對DLL的升級將可以認為是安全的。

如果對一個已經存在的導出類的DLL進行維護,同樣也要注意:不要改動所有的成員變量,包括導出類的父類,無論定義的順序還是數量;不要動所有的虛函數,無論順序還是數量。

總結起來,其實是一句話:導出類的DLL不要導出除了函數以外的任何內容。聽起來是不是有點可笑呢!

事實上,建議你在發布導出類的DLL的時候,重新定義一個類的聲明,這個聲明可以不管原來的類里的成員變量之類的,只把接口函數列在類的聲明里,如下面的例子:
class ClassInterface
{
       privated:
              ClassInterface();
       public:
              static ClassInterface * NewInstance();
              int GetXXX();
              void SetXXX();
              void Function();
};

使用該DLL的應用程序用上面的定義作為ClassInterface的頭文件,便不會有任何可能導致的安全問題。

DLL地獄問是歸根結底是因為DLL當初是作為函數級共享庫設計的,并不能真正提供一個類所必需的信息。類層上的程序復用只有Java和C#生成的類文件才能做到。 

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美在线观看视频一区二区| 亚洲免费婷婷| 欧美在线啊v| 亚洲一区三区视频在线观看| 亚洲美女av电影| 亚洲精品国产品国语在线app | 国产精品美女黄网| 国产精品萝li| 国内外成人免费激情在线视频网站 | 美国十次了思思久久精品导航| 你懂的国产精品永久在线| 欧美激情视频一区二区三区在线播放| 欧美精品一区二区三区在线播放| 欧美三级乱人伦电影| 国产嫩草一区二区三区在线观看 | 欧美黑人多人双交| 国产乱码精品一区二区三区忘忧草| 国产亚洲欧美日韩日本| 亚洲黄色免费| 欧美在线综合视频| 曰韩精品一区二区| 亚洲精品一区中文| 久久久国产成人精品| 欧美成人r级一区二区三区| 亚洲精品一二三| 久久成人免费视频| 欧美日韩一区二| 在线视频成人| 久久福利精品| 在线一区二区三区四区| 久久综合给合久久狠狠色| 国产精品福利网| 亚洲毛片av| 欧美成人免费全部观看天天性色| 亚洲一区二区三区在线观看视频 | 国产精品一区二区三区四区 | 日韩午夜在线| 久热国产精品| 国产综合色产在线精品| 亚洲综合视频1区| 亚洲人成亚洲人成在线观看| 在线亚洲美日韩| 欧美理论电影网| 亚洲欧洲一区二区在线观看| 久久一区二区三区四区五区| 亚洲欧美卡通另类91av| 欧美视频精品在线观看| 99视频精品全部免费在线| 欧美大片在线观看一区| 久久久久久久综合| 99国产精品99久久久久久粉嫩| 狂野欧美激情性xxxx欧美| 国产日韩欧美三级| 性久久久久久久| 亚洲欧美大片| 国产精品亚发布| 欧美一区二区视频在线观看| 中日韩美女免费视频网址在线观看| 欧美精品久久久久久| 日韩视频精品| 一区二区三区福利| 国产精品视频区| 久久成人精品无人区| 亚洲欧美日韩国产一区二区三区| 国产精品99免视看9| 在线视频一区二区| 宅男噜噜噜66一区二区66| 欧美日韩亚洲高清| 亚洲欧美日韩精品久久亚洲区| 宅男噜噜噜66一区二区66| 国产精品自拍在线| 久久久久久自在自线| 久久深夜福利免费观看| 91久久在线播放| 一区二区三区|亚洲午夜| 国产精品剧情在线亚洲| 红桃视频欧美| 欧美国产日韩精品| 欧美日本一区| 欧美一级艳片视频免费观看| 久久精品久久99精品久久| 亚洲国产精品热久久| 日韩视频在线播放| 国产在线精品二区| 最新国产乱人伦偷精品免费网站| 国产精品啊v在线| 久久久欧美一区二区| 免费日韩av电影| 亚洲一区二区综合| 久久精品中文| 亚洲一区免费观看| 久久九九99| 亚洲线精品一区二区三区八戒| 欧美亚洲一区二区在线| 91久久精品国产91久久性色tv| 99国产一区| 在线观看视频一区二区| 亚洲视频久久| 亚洲美女在线观看| 欧美中文字幕视频| 亚洲一卡久久| 欧美丰满少妇xxxbbb| 久久爱另类一区二区小说| 久久综合久久综合九色| 久久躁日日躁aaaaxxxx| 亚洲欧美日韩直播| 欧美福利在线| 久久久亚洲国产天美传媒修理工| 欧美日韩国产不卡| 美玉足脚交一区二区三区图片| 欧美无砖砖区免费| 亚洲欧洲另类| 91久久嫩草影院一区二区| 久久精品三级| 久久综合九色欧美综合狠狠| 国产精品羞羞答答xxdd| 一区二区欧美激情| 亚洲最黄网站| 欧美国产精品va在线观看| 狂野欧美激情性xxxx欧美| 国产女主播一区| 午夜精品久久久久久久久久久久| 亚洲一区二区av电影| 欧美日韩国产美| 亚洲精品视频在线看| 亚洲美女色禁图| 欧美精品在线免费| 亚洲人成在线观看| 日韩五码在线| 欧美激情精品久久久久久免费印度 | 红桃视频欧美| 久久av一区二区三区漫画| 欧美一乱一性一交一视频| 国产精品久久午夜| 亚洲一区二区三区四区中文| 亚洲一区二区精品视频| 欧美性生交xxxxx久久久| 日韩亚洲不卡在线| 亚洲一品av免费观看| 欧美日韩国产成人在线| 99视频有精品| 国产精品美女久久| 先锋影音久久| 麻豆视频一区二区| 最新亚洲激情| 欧美日韩精品二区| 亚洲一区免费观看| 久久久久久久999精品视频| 国产亚洲欧洲一区高清在线观看| 欧美中文字幕在线视频| 欧美成人免费全部| 中文一区字幕| 国产欧美视频在线观看| 欧美一区网站| 亚洲国产成人久久综合一区| 日韩一区二区精品在线观看| 国产精品国产福利国产秒拍 | 久久综合一区二区三区| 91久久黄色| 欧美呦呦网站| 亚洲国产视频直播| 欧美性一区二区| 久久精品99国产精品| 亚洲国产高清高潮精品美女| 亚洲午夜一区二区三区| 国产一区二区三区无遮挡| 欧美成人免费在线| 亚洲欧美在线x视频| 亚洲二区在线观看| 性欧美精品高清| 亚洲国产精品一区二区第一页| 欧美日韩一区免费| 香蕉久久夜色| 亚洲欧洲视频在线| 国产视频一区二区在线观看| 蜜乳av另类精品一区二区| 亚洲视频日本| 欧美激情影音先锋| 欧美中文字幕不卡| 99视频精品全国免费| 一色屋精品亚洲香蕉网站| 欧美午夜在线观看| 美女成人午夜| 欧美中文字幕第一页| 亚洲天堂av在线免费观看| 欧美黄色aaaa| 久久伊人亚洲| 欧美自拍偷拍| 亚洲一区二区三区精品在线观看| 精品成人一区二区三区四区| 欧美亚一区二区| 欧美日韩黄色大片| 欧美区二区三区| 欧美国产一区二区在线观看| 久久精品一区四区| 午夜精品久久久| 亚洲欧美美女| 亚洲一区二区在线免费观看| 亚洲精品偷拍| 亚洲精品欧美激情|