程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> MFC DLL向導(二)

MFC DLL向導(二)

編輯:關於VC++

使用DLL的一個比較嚴重的問題就是編譯器之間的兼容性問題。不同的編譯器對c++函數在二進制級別的實現方式是不同的。所以對基於C++的DLL,如果編譯器不同就有很麻煩的。如果創建的是MFC擴展DLL,就不會存在問題,因為它只能被動態連接到MFC的客戶應用程序。

這裡不是本文討論的重點。

一、重新編譯問題

我們先來看一個在實際中可能遇到的問題:

比如現在建立好了一個DLL導出了CMyClass類,客戶也能正常使用這個DLL,假設CMyClass對象的大小為30字節。如果我們需要修改DLL中的CMyClass類,讓它有相同的函數和成員變量,但是給增加了一個私有的成員變量int類型,現在CMyClass對象的大小就是34字節了。當直接把這個新的DLL給客戶使用替換掉原來30字節大小的DLL,客戶應用程序期望的是30字節大小的對象,而現在卻變成了一個34字節大小的對象,糟糕,客戶程序出錯了。

類似的問題,如果不是導出CMyClass類,而在導出的函數中使用了CMyClass,改變對象的大小仍然會有問題的。這個時候修改這個問題的唯一辦法就是替換客戶程序中的CMyClass的頭文件,全部重新編譯整個應用程序,讓客戶程序使用大小為34字節的對象。

這就是一個嚴重的問題,有的時候如果沒有客戶程序的源代碼,那麼我們就不能使用這個新的DLL了。

二、解決方法 

為了能避免重新編譯客戶程序,這裡介紹兩個方法:(1)使用接口類。(2)使用創建和銷毀類的靜態函數。

1、使用接口類

接口類的也就是創建第二個類,它作為要導出類的接口,所以在導出類改變時,也不需要重新編譯客戶程序,因為接口類沒有發生變化。

假設導出的CMyClass類有兩個函數FunctionA FunctionB。現在創建一個接口類CMyInterface,下面就是在DLL中的CMyInterface類的頭文件的代碼:

# include "MyClass.h"
class _declspec(dllexport) CMyInterface
{
   CMyClass *pmyclass;
   CMyInterface();
   ~CMyInterface();
 public:
   int FunctionA(int);
   int FunctionB(int);
};

而在客戶程序中的頭文件稍不同,不需要INCLUDE語句,因為客戶程序沒有它的拷貝。相反,使用一個CMyClass的向前聲明,即使沒有頭文件也能編譯:

class _declspec(dllexport) CMyInterface
{
   class CMyClass;//向前聲明
   CMyClass *pmyclass;
   CMyInterface();
   ~CMyInterface();
 public:
   int FunctionA(int);
   int FunctionB(int);
};

在DLL中的CMyInterface的實現如下:

CMyInterface::CMyInterface()
{
   pmyclass = new CMyClass();
}
CMyInterface::~CMyInterface()
{
   delete pmyclass;
}
int CMyInterface::FunctionA()
{
   return pmyclass->FunctionA();
}
int CMyInterface::FunctionB()
{
   return pmyclass->FunctionB();
}
.....

對導出類CMyClass的每個成員函數,CMyInterface類都提供自己的對應的函數。客戶程序與CMyClass沒有聯系,這樣任意改CMyClass也不會有問題,因為CMyInterface類的大小沒有發生變化。即使為了能訪問CMyClass中的新增變量而給CMyInterface類加了函數也不會有問題的。

但是這種方法也存在明顯的問題,對導出類的每個函數和成員變量都要對應實現,有的時候這個接口類會很龐大。同時增加了客戶程序調用所需要的時間。增加了程序的開銷。

2、使用靜態函數

還可以使用靜態函數來創建和銷毀類對象。創建一個導出類的時候,增加兩個靜態的公有函數CreateMe()/DestroyMe(),頭文件如下:

class _declspec(dllexport) CMyClass
{
   CMyClass();
   ~CMyClass();
 public:
   static CMyClass *CreateMe();
   static void DestroyMe(CMyClass *ptr);
};
實現函數就是:

CMyClass * CMyClass::CMyClass()
{
 return new CMyClass;
}
void CMyClass::DestroyMe(CMyClass *ptr)
{
 delete ptr;
}

然後象其他類一樣導出CMyClass類,這個時候在客戶程序中使用這個類的方法稍有不同了。如若想創建一個CMyClass對象,就應該是:

CMyClass x;

CMyClass *ptr = CMyClass::CreateMe();

在使用完後刪除:

CMyClass::DestroyMe(ptr);

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved