這通常是由於以數據成員方式在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;
