如何导出标准模板库(STL)类的实例化和包含STL类对象数据成员的类
概要#
本文讨论如何实现下面任务:
- 导出标准模板库(STL)类的实例化。
- 导出包含STL类对象数据成员的类。
注意,您无法导出通用的模板,模板必须实例化才能导出。也就是说,必须提供所有的模板参数,并且在实例化时,模板的参数必须是完全定义的类型。例如stack<int>
实例化STL堆栈类,实例化时强制生成类stack<int>
的所有成员。
还要注意,一些STL容器(map、set、queue、list、deque)无法导出。
更多信息#
从VC++ 5.0开始,可以强制对模板类进行实例化并导出实例化类。导出实例化模板类,可使用以下语法:
导出STL类#
- 在
.dll
和.exe
文件中,必须链接到相同版本的C运行时库dll
。两个都链接msvcrt.lib(Release版本)
或都链接到msvcrtd.lib(Debug版本)
。 - 在
dll
中,在模板的实例化声明中使用__declspec
修饰符,以便从dll
中导出STL类的实例化。 - 在
exe
中,需提供使用extern
和__declspec
修饰的模板实例化声明,以便从dll
中导入类。 这会导致警告 C4231 "nonstandard extension used : 'extern' before template explicit instantiation."
。 您可以忽略此警告。
导出包含STL类对象数据成员的类#
- 在
.dll
和.exe
文件中,必须链接到相同版本的C运行时库dll
。两个都链接msvcrt.lib(Release版本)
或都链接到msvcrtd.lib(Debug版本)
。 - 在
dll
中,在模板的实例化声明中使用__declspec
修饰符,以便从dll
中导出STL类的实例化。
注意:不能跳过上一步,用于创建数据成员的STL类必须导出其实例化。 - 在
dll
中,在类的声明中使用__declspec
修饰符,以便从dll
中导出类。 - 在
exe
中,在类的声明中使用__declspec
修饰符,以便从dll
中导入类。
如果要导出的类有一个或多个基类,那么其基类也必须导出。如果要导出的类中还包含某类类型的数据成员,则还必须导出数据成员类型的类。
注意:一些STL类使用到其它的STL类,这些依赖的类也必须导出。如果使用低于1的警告级别(也就是/W2
、/W3
、/W4
),则必须导出类会出现在编译器警告信息中。/W4
级别编译时,会因为STL而生成大量警告信息,目前不推荐使用此级别警告。
一些STL类包含嵌套类,所以无法导出这些类。例如,deque包含一个嵌套类deque::iterator
。如果导出deque
,将产生警告信息。,提示你必须导出deque::iterator
;如果你导出deque::iterator
则会产生警告信息,提示你必须导出deque
。这是受限于STL的设计,一旦模板类被实例化,它不能被重新实例化和导出。目前唯一可以导出的STL容器是vector
,其它容器(map、set、queue、list、deque)都包含嵌套类无法导出。
导出使用用户定义类型(UDT)作为STL容器模板参数实例化的类时,必须为自定义类型()UDT)重载<
和==
运算符。例如,如果导出vector<MyClass>
,则必须定义MyClass::operator<
和MyClass::==
。这是因为所有的STL容器类都具有成员比较运算操作,需要使用到包含类型的<
和==
运算操作。通常,这些都不被实例化,因为它们没有被使用。当实例化一个模板类时,会生成所有的成员函数,因为STL容器类具有使用到<
和==
的成员函数,所有必须实现它们。如果比较UDT的对象没有意义,也可以在定义operator<
和opeartor==
的时候,简单的返回true
。
当在编译期间发现_DLL
已经定义(当使用/MD
或/MDd
编译与C运行时库的DLL版本链接时,该符号被隐含定义),以下STL类以及对这些类的操作的各种全局运算符和函数,已在C运行时库DLL中导出。因此,无法从DLL中导出它们。z只要导入类也使用相同的C运行时DLL版本,则不应该导致可执行程序出问题。
Header STL template class ------------------------------ <IOSFWD> basic_ios <IOSFWD> <IOSFWD> <IOSFWD> basic_istream <IOSFWD> basic_string (also typedef'd as string and wstring) <IOSFWD> complex <LOCALE> messages <XLOCALE> codecvt <XLOCALE> ctype <XLOCMON> moneypunct <XLOCMON> money_get <XLOCMON> money_put <XLOCNUM> numpunct <XLOCTIME> time_get <XLOCTIME> time_put <XSTRING> basic_string (also typedef'd as string and wstring)
有关使用哪些模板参数以及声明哪些全局函数和操作符的具体细节,请参阅相关的头文件。
// ------------------------------------------- // MYHEADER.H //disable warnings on 255 char debug symbols #pragma warning (disable : 4786) //disable warnings on extern before template instantiation #pragma warning (disable : 4231) #include <vector> // Provide the storage class specifier (extern for an .exe file, null // for DLL) and the __declspec specifier (dllimport for .an .exe file, // dllexport for DLL). // You must define EXP_STL when compiling the DLL. // You can now use this header file in both the .exe file and DLL - a // much safer means of using common declarations than two different // header files. #ifdef EXP_STL # define DECLSPECIFIER __declspec(dllexport) # define EXPIMP_TEMPLATE #else # define DECLSPECIFIER __declspec(dllimport) # define EXPIMP_TEMPLATE extern #endif // Instantiate classes vector<int> and vector<char> // This does not create an object. It only forces the generation of all // of the members of classes vector<int> and vector<char>. It exports // them from the DLL and imports them into the .exe file. EXPIMP_TEMPLATE template class DECLSPECIFIER std::vector<int>; EXPIMP_TEMPLATE template class DECLSPECIFIER std::vector<char>; // Declare/Define a class that contains both a static and non-static // data member of an STL object. // Note that the two template instantiations above are required for // the data members to be accessible. If the instantiations above are // omitted, you may experience an access violation. // Note that since you are exporting a vector of MyClass, you must // provide implementations for the operator < and the operator ==. class DECLSPECIFIER MyClass { public: std::vector<int> VectorOfInts; static std::vector<char> StaticVectorOfChars; public: bool operator < (const MyClass > c) const { return VectorOfInts < c. VectorOfInts; } bool operator == (const MyClass > c) const { return VectorOfInts == c. VectorOfInts; } }; // Instantiate the class vector<MyClass> // This does not create an object. It only forces the generation of // all of the members of the class vector<MyClass>. It exports them // from the DLL and imports them into the .exe file. EXPIMP_TEMPLATE template class DECLSPECIFIER std::vector<MyClass>; // ------------------------------------------- // Compile options needed: /GX /LDd /MDd /D"EXP_STL" // or: /GX /LD /MD /D"EXP_STL" // DLL.CPP #include "MyHeader.h" std::vector<char> MyClass::StaticVectorOfChars; // ------------------------------------------- // Compile options needed: /GX /MDd // or: /GX /MD // EXE.CPP #include <iostream> #include "MyHeader.h" int main () { MyClass x; for (int i=0; i<5; i++) x.VectorOfInts.push_back(i); for (char j=0; j<5; j++) x.StaticVectorOfChars.push_back('a' + j); std::vector<int>::iterator vii = x.VectorOfInts.begin(); while (vii != x.VectorOfInts.end()) { std::cout << *vii; std::cout << " displayed from x.VectorOfInts" << std::endl; vii++; } std::vector<char>::iterator vci = x.StaticVectorOfChars.begin(); while (vci != x.StaticVectorOfChars.end()) { std::cout << *vci; std::cout << " displayed from MyClass::StaticVectorOfChars"; std::cout << std::endl; vci++; } std::vector<MyClass> vy; for (i=0; i=5; i++) vy.push_back(MyClass()); return 1; }
参考#
其它相关信息,请在VC++帮助中搜索以下关键字:Explicit Instantiation(显示实例化)、__declspec、stack、/MD, /ML, /MT, /LD (Use Run-Time Library)。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理