0

我有一个关于 pimpl 模式的问题,也许你们中的一个人可以想出一个我可能错过的解决方案。我已经实现了 pimpl 模式以将我的 dll 中的实现从世界其他地方隐藏起来,但我一直坚持如何隐藏需要从 dll 中导出的结构。下面是我的问题的简单表示(省略了一些部分)

idcom.h

class IDcom_impl;

class IDcom
{
public:
    IDcom_API IDcom();
    void IDcom_API createList();

private:
    std::unique_ptr< IDcom_impl > m_impl;
}

idcom.cpp

IDcom::IDcom() :
    m_impl( new IDcom_impl())
{}

void IDcom::createList()
{
   m_impl->createList();
}

idcom_impl.h

class IDcom_impl
{
public:
    struct IDcom_API ListItem
    {
       std::string var1;
       std::string var2;
    }

    IDcom_impl(){}

    void createList();

    std::vector< ListItem > m_list;
}

如果我想用另一个变量扩展 ListItemstd::string var3并且不破坏 ABI 并从 dll 中获取“listitem”列表,我有什么选择?我知道,为了让应用程序了解有关“ListItem”的一些信息,必须导出这个结构,但这是否足够,这是一个好的设计

4

2 回答 2

0

这里的问题是自动生成的析构函数。要从前向声明中受益,它应该是这样的:

#include <memory>

class IDcom_impl;

class IDcom
{
public:
    IDcom_API ~IDcom();
    IDcom_API IDcom();

    void IDcom_API createList();

private:
    std::unique_ptr< IDcom_impl > m_impl;
};

idcom.cpp

#include "idcom_impl.h"
#include "idcom.h"

IDcom::~IDcom() = default;

IDcom::IDcom() :
    m_impl( new IDcom_impl())
{}

void IDcom::createList()
{
   m_impl->createList();
}

请注意,如果您不声明析构函数,编译器将尝试在每个可能发生破坏的翻译单元中自动生成它。为了能够生成析构函数,编译器必须知道如何销毁字段m_impl,这意味着他必须知道IDcom_impl.

因此,pimpl 模式的优势正在被破坏。

如果您声明析构函数,它将与需要了解的特定翻译单元相关联,IDcom_impl而其他翻译单元现在不需要任何关于IDcom_impl.

于 2020-01-28T15:55:39.670 回答
0

我想我有它,但我需要你们来运行它,以确保我有一个好的设计。所以基本上 pimpl 是正确实现的,但问题是我在 dll 中的数据结构扩展(比如在原始帖子中添加一个新的成员变量,比如 var3 ),应该与应用程序和新版本的 dll 共享(比如v2 )应该与应用程序的当前版本(比如 v2 )和以前的版本(比如 v1 )一起使用,因此无需重新编译应用程序(因此与 v1 兼容)。我只发布了必要的(使阅读更容易:-)),代码可以编译、运行和工作,但对于上述要求和我的原始帖子中的要求,这是一个好的设计。

idcom_global.h:

#if defined( IDCOM_LIBRARY )
 #define IDCOMDLL_API  __declspec( dllexport )
#else
 #define IDCOMDLL_API  __declspec( dllimport )
#endif

idcom.h:

#include "idcom_listitem.h"

class idcomImpl;

class  idcom
{
public:
    IDCOMDLL_API idcom();
    IDCOMDLL_API ~idcom();
    bool IDCOMDLL_API retrieveList( std::vector< ListItem >& list );

private:
    std::unique_ptr< idcomImpl > m_impl;
};

idcom.cpp:

idcom::idcom() :
    m_impl( new idcomImpl())
{}

idcom::~idcom() = default;

bool idcom::retrieveList( std::vector< ListItem >& list )
{
    return m_impl->retrieveList( list );
}

idcomimpl.h:

class idcomImpl
{
public:
    idcomImpl(){};
    ~idcomImpl(){};
    bool retrieveList( std::vector< ListItem >& worklist );
};

idcomimpl.cpp:

bool idcomImpl::retrieveList( std::vector< ListItem >& worklist )
{
....//implementation here
}

idcom_listitem.h:

struct IDCOMDLL_API ListItem
{
    std::string id;
    std::string lastname;
    std::string firstname;
    std::string prefix;

    //expansion of members here in the future e.g. std::string dateOfBirth;
};
于 2020-01-29T08:22:50.297 回答