在我公司的系统上,我们使用一个类来表示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 的强制链接。
我不太确定你的意思,但如果问题是 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中,如果加载失败则抛出异常。
当然,您需要重新编译整个应用程序,但不需要重构它。
如果我记得您必须在 DLL A 中实现第一个列出的构造函数,并对 .DEF 文件中的导出表执行某些操作以导出该构造函数和 VTABLE。
老实说,我不太明白你想做什么,似乎你对“接口”的解释与我们大多数人不同,因为你使用 DLL 来“存储”基础(接口/核心/等)和你的所谓“接口”有“实现”!
如果您现有的解决方案没有围绕界面构建,那么如果您引入它们,则需要进行重大的重新编译,从管理的角度来看很可能不会成功(除非您的经理也是技术极客)。
dll A:通过抽象类定义接口
dll B:接口实现
您能解释一下接口实现是什么意思吗?在理想情况下,接口实际上应该只是标头。即使您有一些默认实现,链接它们的负担会很大吗?
你所描述的本质上是一个插件架构。恐怕没有干净的方法可以通过 dll 来完成此操作。
当然,如果您仅使用 Windows,您可以创建 COM 类(简单)或查找
__declexport
关键字。
是的,在使用 dll 时我会远离模板——它们通常会造成比其价值更多的麻烦。
听着,我可能完全不在这儿,因为我在理解你的问题时遇到了一些困难。 然而,如果我是对的,你想删除 A 和 B 之间的强制联系。
您有接口类,其中包含所有纯虚方法。 您的应用程序使用这种类型的指针与具体对象进行通信。
您的 DLL 实现抽象类,将所有内存分配和销毁保留在 DLL 内。
您在DLL中创建了一个工厂函数,它返回一个抽象类型的指针,但它实际上实例化了一个具体对象。 工厂函数需要在DLL中导出,没有别的。
现在您可以在运行时链接到 dll,调用工厂函数并实例化对象。
这和你想的一样吗?