-3

我正在寻找对 IoC 框架(如 Castle(.NET)或 Java)有一定经验的开发人员的意见。

但是,我正在寻找使用 C++ 实现的类似功能。这不包括 COM,原因我稍后会解释。有没有办法在 C++ 中实现像工厂、抽象工厂或服务提供者这样的模式,主要但不限于 Windows 平台?

具体来说,IoC 应该允许客户端应用程序在运行时发现和加载未知数量的接口实现。

作为我希望的答案:

  1. 指向特定商业或开源 C++ IoC 实现的链接,或
  2. 尝试实施它的个人经验,以及一些主要问题的列表(如果有的话)。

由于意外的反对意见,我必须添加一些额外的规范(OP 可能还不清楚):

  1. 如果实现需要一个封闭的系统是可以的,其中所有组件都需要链接到相同版本的 C++ 运行时库。这不是很好,但可以接受。作为客户端应用程序软件安装的一部分,我一直在研究安装所需版本的 C++ 运行时的软件。IOW,这是一个广泛兼容性的问题,但不是我在这里提出的问题的答案。

  2. 我提到 unique_ptr 因为它是 C++ 标准。自定义智能指针也可以。我希望现在可以更好地探索 unique_ptr 。

  3. 我不是要关于如何将自定义删除器与 unique_ptr 一起使用的代码草案。对于甚至无法编译的代码来说,要少得多。这是得到所有支持的答案。可悲的是,在我评论说“这就像一个试图引导聋子的盲人”之后,惩罚我作为所谓的罪犯并支持所谓的受害者的愤怒被吹得不成比例,导致非理性的反对票和赞成票。我真的很难过,在像 SO 这样的网站上,这样的事情会破坏纯粹的技术问题,并将其变成关于礼貌的个人咆哮。避免在明确要求实际实施经验的问题上投掷毫无头绪的代码草稿会更有礼貌。(一个)

  4. 在没有得到任何明智的答案或良好的链接之后,我花了很多时间尝试自己创建一个示例实现。我在 MSVC 2010 下的 Release 和 Debug 版本中都尝试了它,它按我的预期工作。这是我没有投票接受的答案,因为这是我对自己问题的回答。我仍然希望在这些问题上有实际经验的人提出好的意见。这个答案有 2 个反对票,即使代码按照它所说的那样做,如果你真的尝试编译和运行它。

(a) 根据麦格劳-希尔美国成语和短语动词词典和剑桥成语词典,链接到引起正义愤慨的冒犯性、不礼貌和粗鲁的短语的含义:

盲人引导盲人

4

2 回答 2

4

如果我们看一下unique_ptr类,我们可以看到默认情况下它使用default_delete类的实例。default_delete 类具有以下方法: void operator()(T *ptr) const. 要实现自定义删除器,您需要创建一个类似于以下内容的类(代码改编自此处):

class MyDeleter
{
public:
    MyDeleter(FactoryReference *f)
    {
        m_factoryRef = f;
    }
    void operator()(IFace *ptr) const
    {
        delete ptr;
        m_factoryRef->unloadDLL();
    }
private:
    FactoryReference *m_factoryRef;
};

std::unique_ptr<IFace, MyDeleter> GetIFace()
{
    FactoryReferece *myFactory = /* a factory reference */;
    return new std::unique_ptr<IFace, MyDeleter>(myFactory->getIFaceSubclass(), MyDeleter(myFactory));
}
于 2013-09-11T02:21:12.233 回答
-1

可以办到。这是我测试的示例实现的框架。它是用 Visual C++/VS 2010 构建的。

接口在头文件 Iface.h 中声明:

#pragma once

#include <memory>
#include <string>

#ifdef IFACE_EXPORTS
#define IFACE_API __declspec(dllexport)
#else
#define IFACE_API __declspec(dllimport)
#endif

namespace Generic
{

class Iface
{
public:
   virtual void DoSomething(std::string const&) = 0; 
   virtual ~Iface() {};
};

IFACE_API std::unique_ptr<Iface> GetIface();

typedef std::unique_ptr<Iface> (*GetIfaceType)();

}

几个 Dll 实现了这个接口,而第三个 Dll 称为 Factory,动态加载其中一个。反过来,Factory 导出一个函数供应用程序使用,该函数将隐式链接到它(即通过导出库。)

这是 FactoryIface.h,将包含在客户端应用程序中:

#pragma once

#include <memory>
#include "Iface.h"

#ifdef FACTORY_EXPORTS
#define FACTORY_API __declspec(dllexport)
#else
#define FACTORY_API __declspec(dllimport)
#endif

class FACTORY_API IFaceCustomDeleter
{
   void* hMod_;
public:
   IFaceCustomDeleter(void* hMod=nullptr);
   void operator()(Generic::Iface* ptr);
};

FACTORY_API std::unique_ptr<Generic::Iface, IFaceCustomDeleter> FactoryGetIface();

请注意,必须导出自定义删除器类。那是我忘记做的第一件事。构建客户端应用程序很快就指向了它。下面是关键部分,Factory Dll 中 FactoryGetIface() 的实现:

// A trick to get decorated name of exported function
std::string DecoratedName;

namespace Generic
{
   std::unique_ptr<Iface> GetIface()
   {
      DecoratedName = __FUNCDNAME__;
      return std::unique_ptr<Iface>(nullptr);
   }
}

using namespace Generic;

// for keeping Iface from dynamically loaded DLL
std::unique_ptr<Iface> ExternalIface;

// Custome deleter implementation

IFaceCustomDeleter::IFaceCustomDeleter(void* hMod) 
   : hMod_(hMod) 
{
}

void IFaceCustomDeleter::operator()(Iface* ptr)
{
   ExternalIface.reset(nullptr);
   if(hMod_)
      ::FreeLibrary((HMODULE)hMod_);
}


FACTORY_API std::unique_ptr<Generic::Iface, IFaceCustomDeleter> FactoryGetIface()
{
   // determine path of DLL to load for Iface implementation
   auto path = L".\\IfaceImplB.dll";

   auto hmod = ::LoadLibrary(path);
   if(hmod)
   {
      GetIface(); // get decorated name

      GetIfaceType ptrGetIface;
      ptrGetIface = (GetIfaceType)::GetProcAddress(hmod, DecoratedName.c_str());
      // Alternatively, use full decorated name like below:
      //ptrGetIface = (GetIfaceType)::GetProcAddress(hmod,
      //"?GetIface@Generic@@YA?AV?$unique_ptr@VIface@Generic@@U?$default_delete@VIface@Generic@@@std@@@std@@XZ");

      if(ptrGetIface)
      {
         ExternalIface = ptrGetIface();
         ExternalIface->DoSomething("Hello from Factory");
         IFaceCustomDeleter del(hmod);
         return std::unique_ptr<Generic::Iface, IFaceCustomDeleter>(ExternalIface.get(), del);
      }
   }

   IFaceCustomDeleter del;
   return std::unique_ptr<Generic::Iface, IFaceCustomDeleter>(nullptr, del);
}

请注意,Dll 路径是硬编码的:这只是一个示例,但它可以编译和工作。在实际应用中,可以有,例如。解析一些指定要加载的 Dll 的 xml。

通过 Factory 使用 Iface 的非常基本的控制台应用程序如下所示:

#include "FactoryIface.h"

int _tmain(int argc, _TCHAR* argv[])
{
   {
      std::unique_ptr<Generic::Iface, IFaceCustomDeleter> iface = FactoryGetIface();
      iface->DoSomething("Hello from Factory user");
   }

    return 0;
}

当我运行它时,我得到如下输出:

In IfaceImplB constructor
Doing something: Hello from Factory
Doing something: Hello from Factory user
In IfaceImplB destructor
于 2013-09-12T21:36:53.223 回答