且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在DLL中实现类计数器?

更新时间:2023-12-02 16:10:34

确实,您无法导出类模板。这是没有用的,因为你有所有的类模板写在头文件中,所以实际上不需要导出才能使用代码。
相反,您必须导出类实例化,然后使用extern关键字:

It is true that you cannot export a class template. This is even useless, since you have all the class template written in the header file, so no export is actually required to be able to use the code. Instead, you have to export the class instantiation, and later use it with the "extern" keyword:

这是编译库时的头文件:

This is the header file when compiling the library:

class SBase{ ... }

template class __declspec(dllexport) Bridge<S0, SBase>;
class S0 : public Bridge<S0, SBase>
{ ... }
template class __declspec(dllexport) Bridge<S1, SBase>;
class S1 : public Bridge<S1, SBase>
{ ... }
template class __declspec(dllexport) Bridge<S2, SBase>;
class S2 : public Bridge<S2, SBase>
{ ... }

这是构建客户端代码时的头文件:

And this is the header file when building the client code:

class SBase{ ... }

extern template class __declspec(dllimport) Bridge<S0, SBase>;
class S0 : public Bridge<S0, SBase>
{ ... }
extern template class __declspec(dllimport) Bridge<S1, SBase>;
class S1 : public Bridge<S1, SBase>
{ ... }
extern template class __declspec(dllimport) Bridge<S2, SBase>;
class S2 : public Bridge<S2, SBase>
{ ... }

所以现在,链接器将通过所有您的程序,不仅在您的编译模块。

So now, the linker will search for this classes through all your program, not only in your compiling module.

这应该是typedefed,以获得不同的输出使用相同的代码:

This should be typedefed, in order to get the different outputs using the same code:

#ifdef LIBRARY_BUILD
#define EXPORT __declspec(dllexport)
#define TEMPLATE_EXPORT
#else
#define EXPORT __declspec(dllimport)
#define TEMPLATE_EXPORT extern
#endif

class SBase{ ... }

TEMPLATE_EXPORT template class EXPORT Bridge<S0, SBase>;
class S0 : public Bridge<S0, SBase>
{ ... }
TEMPLATE_EXPORT template class EXPORT Bridge<S1, SBase>;
class S1 : public Bridge<S1, SBase>
{ ... }
TEMPLATE_EXPORT template class EXPORT Bridge<S2, SBase>;
class S2 : public Bridge<S2, SBase>
{ ... }

必须在具有静态成员的所有模板类中完成,所以所有的模板类只有一个实例化的成员,而不是每个编译模块。

This have to be done in ALL template classes with static members, so all the template classes have got only ONE instantiation of the members, instead of one per compilation module.

您可以在这里获得更多信息:
共享库中的类和静态变量

You can have further information here: classes and static variables in shared libraries

编辑:
重新阅读你的问题,我会声明为extern你的模板基类(因为它是一个静态成员),而不是特定的:

Re-reading your question, I would declare as extern your template base class (since it is the one with the static member), not the particular ones:

TEMPLATE_EXPORT template class EXPORT Counter<SBase>;

所以现在,你可以有任何SBase的派生类,所有的都将依赖于相同的Counter类,而不需要声明自己为外部人。
当然,如果SBase在某个库中,那么它应该也被声明为extern(通常的方式,只是__declspec(dllexport),因为它不是一个模板)。

So now, you can have any SBase's derived class and all will be relying on the same Counter class, without the need to declare themselves as extern. Of course, if SBase is in some library, it should be declared also itself as extern (in the normal way, just __declspec(dllexport), since it is not a template).