【问题标题】:how to use an exported class (__declspec(dllexport))in an stl template?如何在 stl 模板中使用导出的类 (__declspec(dllexport))?
【发布时间】:2010-11-23 06:47:01
【问题描述】:

我正在使用导出的类

class __declspec(dllexport) myclass  
{  
private:  
template __declspec(dllexport) class std::map<myclass*,int>;    
std::map<myclass*,int>m_map;  
//something  
};    

当我这样做时,我收到一条警告 C4251,说 m_map:class 'std::map<_kty>' 需要有 dll 接口供 myclass 类的客户端使用。
关于如何解决这个问题的任何想法?
阿图尔

【问题讨论】:

    标签: c++ templates dllexport


    【解决方案1】:

    您不应该在使用 DLL 的代码将使用的头文件中使用 __declspec(dllexport),因为它们需要使用 __declspec(dllimport)。

    因此,如果设置了特定的其他定义,您应该创建一个使用 dllexport 的宏,如果没有设置,则使用 dllimport。

    在某处的通用标题中:

    #ifdef EXPORTING_FOO
    #define FOO_API __declspec(dllexport)
    #else
    #define FOO_API __declspec(dllimport)
    #endif
    

    你可以实例化一个模板:

    extern template class FOO_API Templ<MyClass, int >;
    

    在包含的标题中。注意这里的外部。 在一个编译单元内声明相同但没有 extern 和 FOO_API,因此:

    template class Templ<MyClass, int >;
    

    这意味着使用您的库的代码不会实例化模板,而是使用您库中的模板。这在模板具有虚拟成员时特别有用。

    如果模板来自标准库或 boost,则使用您的代码必须使用与您相同的版本,否则可能会出现严重问题。

    鉴于在您自己的示例中,它出现在私有区域中,这表明您希望将其从库的界面中重构出来。理想情况下,您的库应该只公开除前向声明之外的公共方法和成员。私有复制构造函数和分配以使类不可复制和不可分配很好-它们实际上并不是实现的一部分,它们是您的类接口的一部分(您是说您不能复制或分配它们)。

    【讨论】:

    • 这就是我在 2010 年以前的做法,但现在实际上我有一个 stdafx.h 文件或类似文件,它包含在所有项目源中,但不包含在外部用户源中,它定义了 FOO_API 或其他.然后,标头会简单地执行 #ifndef FOO_API 并且也会执行 #pragma 注释库。
    【解决方案2】:

    您不能导出具有未导出成员的类。一个可能的解决方案是使用 Pimpl 成语。使用 Pimpl,用户不知道该类的成员。所以不需要导出 stl 类。有关 pimpl 的进一步阅读,请检查以下内容: http://c2.com/cgi/wiki?PimplIdiom 或 http://www.gamedev.net/reference/articles/article1794.asp

    例子:

    myclass.h:

    class __declspec(dllexport) myclass
    {
    public:
        myclass();
        virtual ~myclass();
    private:
        myclass(const myclass& other) {}
        myclass& operator=(const myclass& rhs) {return *this;}
        myclassImpl* m_Pimpl;
    };
    

    myclass.cpp:

    #include "myclass.h"
    #include "myclassImpl.h"
    
    
    myclass::myclass()
        :m_Pimpl(new myclassImpl())
    {}
    
    myclass::~myclass() {
        delete m_Pimpl;
    }
    

    myclassImpl.h:

    class myclassImpl {
    private:
        std::map<myclass*,int>m_map;
    };
    

    【讨论】:

    • @David,你能详细说明一下这个 Pimpl 成语吗?
    • 很好,但是你给自己造成了更多的问题,使析构函数虚拟化。没有人会从它们中派生出来,因为如果你想要多态性,你就把它放到 pImpl 中。您还应该使您的课程不可复制且不可分配。
    • @CashCow 你是对的 - 代码没有妥善处理分配和复制。但它可以由库的用户继承。
    猜你喜欢
    • 1970-01-01
    • 2018-08-05
    • 2012-04-14
    • 2016-02-13
    • 2016-03-25
    • 2023-01-26
    • 2015-02-24
    • 2011-03-28
    • 2016-02-01
    相关资源
    最近更新 更多