如何在DLL中实现类计数器? [英] How to implement a class counter in DLL?

查看:146
本文介绍了如何在DLL中实现类计数器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

到目前为止,我有:

  // TypeCounter.h 

template< typename Base> ;
类计数器:public Base
{
protected:
static int typeIndexCounter;
};

template< typename T,typename Base>
class Bridge:public Counter< Base>
{
public:
virtual〜Bridge(){}

virtual int GetTypeIndex()const
{
return TypeIndex
}

static int TypeIndex()
{
static int typeIndex = typeIndexCounter ++;
return typeIndex;
}
};

//静态变量定义
模板< typename Base>
int Counter< Base> :: typeIndexCounter;

用例如下:

  class SBase 
{...}
class S0:public Bridge< S0,SBase>
{...}
类S1:public Bridge< S1,SBase>
{...}
class S2:public Bridge< S2,SBase>
{...}

类,我可以计算它有多少派生它(如果它曾经被实例化,当然)。



问题是, 计数器类在DLL中。



如果我有这个DLL的多个用户, Bridge Counter ,则 TypeIndex()在这些用户对于同一 T 不同。



我试图把 __ declspec dluxport) 之前和,但在用户端有编译错误用户端会通过定义一个宏来将 export 更改为 import

错误,它也是一个错误的方法,因为不应该导出类模板。



所以我想确保 TypeIndex即使对于同一个 T T

解决方案


$ b

这是真的,你不能导出类​​模板。这甚至没有用,因为你有所有的类模板写在头文件中,所以实际上不需要导出来使用代码。
相反,您必须导出类实例化,并稍后通过extern关键字使用它:



这是编译库时的头文件:

  class SBase {...} 

模板类别__declspec(dllexport)Bridge< S0,SBase> ;;
class S0:public Bridge< S0,SBase>
{...}
模板类__declspec(dllexport)Bridge< S1,SBase> ;;
class S1:public Bridge< S1,SBase>
{...}
模板类__declspec(dllexport)Bridge< S2,SBase> ;;
class S2:public Bridge< S2,SBase>
{...}

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

  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>
{...}

现在,链接器将通过所有



这应该是typedefed,为了得到不同的输出使用相同的代码:

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

class SBase {...}

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

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



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



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

  TEMPLATE_EXPORT模板类EXPORT计数器< SBase> ;; 

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


So far I have:

// TypeCounter.h

template <typename Base>
class Counter : public Base
{
protected:
    static int typeIndexCounter;
};

template <typename T, typename Base>
class Bridge : public Counter<Base>
{
public:
    virtual ~Bridge() {}

    virtual int GetTypeIndex() const
    {
        return TypeIndex();
    }

    static int TypeIndex()
    {
        static int typeIndex = typeIndexCounter++;
        return typeIndex;
    }
};

// static variable definition
template <typename Base>
int Counter<Base>::typeIndexCounter;

Use case is like:

class SBase
{ ... }
class S0 : public Bridge<S0, SBase>
{ ... }
class S1 : public Bridge<S1, SBase>
{ ... }
class S2 : public Bridge<S2, SBase>
{ ... }

So for each kind of Base class, I can count how many derives it has (if it has ever been instantiated, of course).

The problem is that, this Counter class is in a DLL.

If I have multiple users of this DLL, then each user would instantiate its own Bridge and Counter, then the TypeIndex() can be different among these users for the same T.

I tried to put __declspec(dllexport) before Counter and Bridge, but there are compile errors on the user side (the user side would change export to import, by defining a macro).
Despite the errors, it is also a wrong approach, since one should not export class template.

So I want to make sure that the TypeIndex() keep the same for certain T, even if there are many instantiations for the same T, how can I achieve this?

Thanks!

解决方案

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.

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

EDIT: 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>;

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).

这篇关于如何在DLL中实现类计数器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆