ОК, поэтому я прочитал несколько вопросов и статей на эту тему, и я чувствую, что понимаю основы, но у меня все еще проблемы.
У меня есть DLL, которая экспортирует класс, в качестве члена которого используется std :: string.
Моя основная программа содержит классы, которые также имеют строки, и использует DLL.
Если я скомпилирую DLL в VS2010, я получу следующие предупреждения:
warning C4251: 'MyClass::data' : class 'std::basic_string<_Elem,_Traits,_Ax>' needs to have dll-interface to be used by clients of class 'MyClass'
Когда я компилирую EXE, я получаю те же предупреждения, но ошибок нет, и программа компилируется и запускается. На самом деле, это большой проект, поэтому я получаю около 40 предупреждений, и я не слишком заинтересован в этом. (В качестве дополнительного наблюдения эти предупреждения отсутствуют при компиляции с VS2008)
Итак, я прочитал об этом предупреждении, и оно привело меня к этой статье MS:
http://support.microsoft.com/default.aspx?scid=KB;EN-US;168958
в котором рассказывается, как экспортировать шаблон STL из DLL, чтобы получить предупреждения, которые я получал.
Проблема в том, что, когда я добавляю следующие строки для удаления предупреждений:
EXPIMP_TEMPLATE template class DECLSPECIFIER std::allocator<char>;
EXPIMP_TEMPLATE template class DECLSPECIFIER std::basic_string< char, std::char_traits<char>, std::allocator<char> >;
DLL компилируется без предупреждений, но когда я компилирую свой EXE, компоновщик подбрасывает:
2>SampleDLL.lib(SampleDLL.dll) : error LNK2005: "public: __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::~basic_string<char,struct std::char_traits<char>,class std::allocator<char> >(void)" (??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ) already defined in OtherClass.obj
2>SampleDLL.lib(SampleDLL.dll) : error LNK2005: "public: unsigned int __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::size(void)const " (?size@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEIXZ) already defined in OtherClass.obj
И DLL, и EXE компилируются с одинаковыми параметрами генерации кода. Я могу использовать MT на обоих или MD, и результаты одинаковы.
Я включаю код из свернутой программы-примера на случай, если что-то упущу выше.
Мой главный вопрос: можно ли исправить ошибки LNK2005 или можно просто игнорировать предупреждения C4251?
Редактировать: Так что я прочитал немного больше, и похоже, что если std :: string, который использует класс DLL, является закрытой переменной, доступ к которой имеют только функции-члены, это может быть безопасно игнорировать предупреждение ... Есть комментарии? Это шаг в правильном направлении?
код DLL:
#pragma once
#include <exception>
#include <string>
#ifdef SAMPLEDLL_EXPORTS
# define DECLSPECIFIER __declspec(dllexport)
# define EXPIMP_TEMPLATE
#else
# define DECLSPECIFIER __declspec(dllimport)
# define EXPIMP_TEMPLATE extern
#endif
//disable warnings on extern before template instantiation (per MS KB article)
#pragma warning (disable : 4231)
//std::basic_string depends on this allocator, so it must also be exported.
EXPIMP_TEMPLATE template class DECLSPECIFIER std::allocator<char>;
//std::string is a typedef, so you cannot export it. You must export std::basic_string
EXPIMP_TEMPLATE template class DECLSPECIFIER std::basic_string< char, std::char_traits<char>, std::allocator<char> >;
#pragma warning (default : 4231)
class DECLSPECIFIER MyClass
{
public:
std::string getData(); //returns 'data', body in CPP file
private:
std::string data;
int data2;
};
//in SampleDLL.cpp file...
std::string MyClass::getData() { return data; }
EXE-код:
#include <iostream>
#include "SampleDLL.h"
using namespace std;
void main()
{
MyClass class1;
cout << class1.getData() << endl;
}