1. 程式人生 > >消除needs to have dll-interface to be used警告

消除needs to have dll-interface to be used警告

這通常是由於以資料成員方式在DLL匯出類中使用了模板類造成的,不同的地方的vector的實現可能不一樣所造成的問題。所以我們應該將vector所依賴的模板類也匯出。比如:
#include <iostream>
#include <vector>
using namespace std;

class __declspec( dllexport ) Test
{
public:
std::vector<int> m_objCon;
};

int main()
{


return 0;
}

這會導致這個警告:
warning C4251: “Test::m_objCon”: class“std::vector<_Ty>”需要有 dll 介面由 class“Test”的客戶端使用 
1>        with
1>        [
1>            _Ty=int
1>        ]
這個問題主要要描述的是不同的地方的vector的實現可能不一樣所造成的問題。所以我們應該將其匯出。有很多方法可以解決這個問題的。

第一種: 無視它或者#pragma warnind( disable: 4251 )
第二種:將該資料改為指標方式:
class __declspec( dllexport ) Test
{
public:
std::vector<int>* m_objCon;
};
然後在建構函式和解構函式中分別初始化和釋放它。
第三種:
將該模板類及其依賴類匯出。
#include <iostream>
#include <vector>
using namespace std;

class __declspec( dllexport ) Test
{
public:
template  class __declspec( dllexport ) std::allocator<int>;
template  class __declspec( dllexport ) std::vector<int, std::allocator<int> >;
public:

std::vector<int> m_objCon;
};

int main()
{


return 0;
}
這 種方法要注意的是必須要把要匯出模板類的模板資料成員一併匯出。有點類似於顯式例項化。比如說你要匯出boost::shared_ptr就還必須將其依 賴的shared_count一併匯出。匯出map還需要匯出對應pair等等。很麻煩啦~所以我們還是選擇第四種吧。

第四種:Impl。
#include <iostream>
#include <vector>
using namespace std;

// 這些放到.h中
class Test_imp;
class __declspec( dllexport ) Test
{
// 建構函式中初始化 析構中釋放m_pImp;
void test();
public:
Test_imp* m_pImp;
};

// 這個類放到cpp中去
class  Test_imp
{
public:
void test(){}
std::vector<int> m_objCon;
};

// 放到cpp中
void Test::test()
{
m_pImp->test();
}

int main()
{


return 0;
}

個人推薦第二種和第四種,反對第一種。畢竟掩耳盜鈴不是好習慣~~
第四種除了可以解決上面的問題之外還可以隱藏程式碼,當然多了一個橋接的過程。



 

 

 

程式中消除warning有兩種方法:消極一點不去理他,反正不是error:-);積極一點,則想辦法去掉。去掉又用兩種方法:一種使用#pragma warning(disable: xxxx),眼不見,心不煩;另外就是找出解決問題的辦法了。
今天做dll庫時,在struct中用到了stl:
class CLASS_TEST
{
    …
private:
    std::vector<MY_STRUCT> m_structs;
}
但 是編譯時,vs2005給出了warning C4251: ‘CLASS_TEST::m_structs’ : class ‘std::vector<_Ty>’ needs to have dll-interface to be used by clients of class ‘CLASS_TEST’的警告資訊。費了很大的勁才解決掉,記錄下來。

在標頭檔案中,定義巨集
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif

現在,在變數m_structs前,新增:
template class MYDLL_API std::allocator<myStruct>;
template class MYDLL_API std::vector<myStruct, std::allocator<myStruct> >;
這樣,即可以了。


另一篇:

1:情況一
如果類的定義裡面僅含有 編譯器內建的型別變數, int, float 等等. 或者成員函式僅使用了這些變數作為引數, 那麼很簡單.
直接
class __declspec(dllexport) YourClass

{
}
就行了.

2:情況二
如果類內部使用了別的類, 那麼別的類最好也匯出, 不然, 首先編譯的時候會出現編譯警告:
warning C4251: needs to have dll-interface 
意思是,你使用另外的一些型別/介面, 但是這些型別或介面沒有匯出. 當你的client使用這些型別/介面的時候, 會出錯!
class __declspec(dllexport) YourClass

{
   YourAnatherClass m_data; // 這裡會 出現 warning 4251. 如果YourAnatherClass 沒有匯出的話.
}
解決辦法就是: 在YourAnatherClass定義的地方加上
class __declspec(dllexport) YourAnatherClass 
{
}
如上, 當你的YourAnatherClass沒有匯出的時候, dll的使用方會出現連結錯誤

3:情況三
當類的內部使用了STL模板的時候, 也會出現C4251警告, 情況會有所不同
class __declspec(dllexport) YourClass

{
   vector<int> m_data; // 這裡會 出現 warning 4251. 因為vector<int>型別沒有被匯出
}
上面的使用模板(無論是stl模板,還是自定義模板)的程式碼,編譯dll時會出現C4251警告, 但是dll的使用方, 卻不會出現連結錯誤!!!
這個因為, dll的使用方那裡也有一套模板的定義, 當他們使用那個vector<int>的時候, 雖沒有匯出, 但是使用者自己也有一套STL模板(或者是自定義的模板),使用者會利用自己的模板例項化這個dll中沒有匯出的東西!

所以, 對於因為使用STL(或模板)出現的c4251警告, 關閉之即可
#pragma warning(push)
#pragma warning(disable:4251)
//your declarations that cause 4251
#pragma warning(pop)

若想不使用通過關閉警告的方式關閉警告, 那麼就這樣
1)對於使用者自定義的模板
   template class DLLImportExportMacro SomeTemplate<int>;
   SomeTemplate<int> y;
2)對於STL的模板
     template class DLLImportExportMacro std::allocator<int>
     template class DLLImportExportMacro std::vector<int,
      std::allocator<int> >;
     vector<int> m_data;