将类设为“Interfaceable”

问题描述 投票:0回答:5

在我公司的系统上,我们使用一个类来表示bean。它只是使用 boost::variant 和一些序列化/反序列化内容的信息持有者。它运行良好,但我们有一个问题:它不是通过接口,并且由于我们通过 dll 使用模块化,因此为其构建接口变得非常复杂,因为它几乎用在我们应用程序的每个部分,而且遗憾的是接口C++ 上的(抽象类)必须通过指针来访问,这使得重构整个系统几乎不可能。

我们的结构是:

dll A:通过抽象类定义接口
dll B:接口实现

有一种轻松的方法可以实现这一点(也许使用模板,我不知道),或者我应该忘记让这项工作正常进行,而只是将所有内容与 dll B 链接起来?

谢谢

编辑:这是我的例子。
这是在 dll A 上
BeanProtocol 是 N 个数据协议项的持有者,这些数据协议项通过索引访问。

class DataProtocol;

class UTILS_EXPORT BeanProtocol
{
public:
  virtual DataProtocol& get(const unsigned int  ) const
  {
    throw std::runtime_error("Not implemented");
  }

  virtual void getFields(std::list<unsigned int>&) const
  {
    throw std::runtime_error("Not implemented");
  }

  virtual DataProtocol& operator[](const unsigned int )
  {
    throw std::runtime_error("Not implemented");
  }

  virtual DataProtocol& operator[](const unsigned int ) const
  {
    throw std::runtime_error("Not implemented");
  }

  virtual void fromString(const std::string&) 
  {
    throw std::runtime_error("Not implemented");
  }
  
  virtual std::string toString() const
  {
    throw std::runtime_error("Not implemented");
  }

  virtual void fromBinary(const std::string&)
  {
    throw std::runtime_error("Not implemented");
  }

  virtual std::string toBinary() const
  {
    throw std::runtime_error("Not implemented");
  }

  virtual BeanProtocol& operator=(const BeanProtocol&)
  {
    throw std::runtime_error("Not implemented");
  }

  virtual bool operator==(const BeanProtocol&) const
  {
    throw std::runtime_error("Not implemented");
  }

  virtual bool operator!=(const BeanProtocol&) const
  {
    throw std::runtime_error("Not implemented");
  }

  virtual bool operator==(const char*) const
  {
    throw std::runtime_error("Not implemented");
  }

  virtual bool hasKey(unsigned int field) const
  {
    throw std::runtime_error("Not implemented");
  }
};

另一个类(名为 GenericBean)实现它。这是我找到的唯一方法,但现在我想将其变成一个真正的接口并删除 UTILS_EXPORT (这是一个 _declspec 宏),最后删除 B 与 A 的强制链接。

c++ interface
5个回答
1
投票

我不太确定你的意思,但如果问题是 BeanProtocol 不是一个指针,那么你不能让它包装一个指向另一个类(比如 BeanPointerImpl)的指针,然后你可以从你的 DLL 加载它。

class BeanProtocol
{
  private BeanProtocolImpl m_impl;
  public:
  DataProtocol& get(const unsigned int index ) const
  {
    if(! m_impl)
    { 
       load_impl(get_appropriate_dll()) 
    }
    return m_impl->get(index);
  }

... BeanProtocol 上的所有其他方法依此类推。

然后,您可以将插件实现为 BeanProtocolImpl 的不同子类,从 DLL(本例中为 DLL B)导出它们,并废弃 DLL A。

在这个例子中,我假设

load_impl
加载DLL,调用工厂方法来获取BeanProtocolImpl的实现并将其存储在m_impl中,如果加载失败则抛出异常。

当然,您需要重新编译整个应用程序,但不需要重构它。


0
投票

如果我记得您必须在 DLL A 中实现第一个列出的构造函数,并对 .DEF 文件中的导出表执行某些操作以导出该构造函数和 VTABLE。


0
投票

老实说,我不太明白你想做什么,似乎你对“接口”的解释与我们大多数人不同,因为你使用 DLL 来“存储”基础(接口/核心/等)和你的所谓“接口”有“实现”!

如果您现有的解决方案没有围绕界面构建,那么如果您引入它们,则需要进行重大的重新编译,从管理的角度来看很可能不会成功(除非您的经理也是技术极客)。


0
投票

dll A:通过抽象类定义接口

dll B:接口实现

您能解释一下接口实现是什么意思吗?在理想情况下,接口实际上应该只是标头。即使您有一些默认实现,链接它们的负担会很大吗?

你所描述的本质上是一个插件架构。恐怕没有干净的方法可以通过 dll 来完成此操作。

当然,如果您仅使用 Windows,您可以创建 COM 类(简单)或查找

__declexport
关键字。

是的,在使用 dll 时我会远离模板——它们通常会造成比其价值更多的麻烦。


0
投票

听着,我可能完全不在这儿,因为我在理解你的问题时遇到了一些困难。 然而,如果我是对的,你想删除 A 和 B 之间的强制联系。

您有接口类,其中包含所有纯虚方法。 您的应用程序使用这种类型的指针与具体对象进行通信。

您的 DLL 实现抽象类,将所有内存分配和销毁保留在 DLL 内。

您在DLL中创建了一个工厂函数,它返回一个抽象类型的指针,但它实际上实例化了一个具体对象。 工厂函数需要在DLL中导出,没有别的。

现在您可以在运行时链接到 dll,调用工厂函数并实例化对象。

这和你想的一样吗?

© www.soinside.com 2019 - 2024. All rights reserved.