使用抽象基类与(非虚拟)模板方法

时间:2015-03-10 21:19:24

标签: c++ templates dynamic-cast

我最近使用我以前从未见过的技术在我们的产品中运行代码。我正在寻找参考,看看这是否是一种既定的技术(我不会把它称为模式),如果是这样,那么理解的风险和收益是什么。请注意,出于商业原因,我们不能使用C ++ 11构造。

下面的示例代码说明了该技术的一种用法。我们有两个从抽象基类派生的适配器,它定义了客户端要访问的通用API。

一个客户决定需要公开改编的班级。仅为此简单示例,客户端使用类型标记switch语句来发现类型。

为了实现,作者定义了抽象基类。在其中,他有一个嵌套的类模板,它包含一个纯虚拟的getter返回指向类型T的指针。他还有一个非虚拟的模板化方法,可以为所需的每种类型实例化(最好参考下面的例子)。

适配器派生自抽象基类,它是嵌套模板类。然后他们实现虚拟吸气剂。

客户端将知道适配类的类型,并可以使用适当的类型调用非虚拟模板化基类方法。这又调用了适配器类的模板方法。这里的主要目标似乎是让客户端免于使用dynamic_cast<>(),或者需要自己定义模板。

#include <iostream>
#include <string>

enum ObjectProxyType {
  SimpleProxy,
  CompoundProxy
};

class ObjectProxyIfc
{
protected:
   ObjectProxyIfc() {}

public:
   virtual ~ObjectProxyIfc() {}

   virtual ObjectProxyType type() const = 0;

   virtual std::string name() = 0;
   // adapter method (example)

   template<class T>
   class ProxyGetterIfc
   {
   public:
      virtual const T* get() const = 0;
   };

   template <typename T>
   const T* get() const
   {
      // this templated method is non-virtual, and should not be
      // overridden/shadowed by derived classes. Adapters will derive
      // from ObjectProxyIfc *and*
      // ObjectProxyIfc::ProxyGetterIfc<type-to-be-wrapped>, and then
      // implement the wrapped virtual method, called here.
      //
      ProxyGetterIfc<T> *getter = dynamic_cast<ProxyGetterIfc<T> *>(const_cast<ObjectProxyIfc *>(this));
      return getter ? getter->get() : 0;
   }
};

class SimpleObject
{
public:
   SimpleObject() {};
   ~SimpleObject() {};

   std::string objName() const { return "SimpleObject"; }
};

class SimpleObjectProxy : public ObjectProxyIfc,
                         public ObjectProxyIfc::ProxyGetterIfc<SimpleObject> 
{
public:
   SimpleObjectProxy(SimpleObject *obj) : obj_(obj) {};
   ~SimpleObjectProxy() {};

   virtual ObjectProxyType type() const { return SimpleProxy; }

   virtual std::string name()
   {
      // adapter for wrapped object
      return obj_->objName();
   }

   virtual const SimpleObject *get() const {
     return obj_;
   } 

private:
   SimpleObject  *obj_;
};

ObjectProxyIfc *oPI()
{
   return new SimpleObjectProxy(new SimpleObject());
}

class CompoundObject
{
public:
   CompoundObject(const std::string &annotation) : annotation_(annotation) {};
   ~CompoundObject() {};

   std::string objName() const { return "CompoundObject"; }

   std::string annotation() const
   {
      // No adapter method is available for this item!
      return annotation_;
   }

private:
   std::string annotation_;
};

class CompoundObjectProxy : public ObjectProxyIfc,
                            public ObjectProxyIfc::ProxyGetterIfc<CompoundObject *>
{
public:
   CompoundObjectProxy(CompoundObject **objs) : objs_(objs) {};
   ~CompoundObjectProxy() {};

   virtual ObjectProxyType type() const { return CompoundProxy; }

   virtual std::string name()
   {
      // adapter for wrapped object
      return objs_[0]->objName();
   }

   virtual CompoundObject *const *get() const {
      return const_cast< CompoundObject *const *>(objs_);
   }

private:
   CompoundObject  **objs_;
};

ObjectProxyIfc *oPI2()
{
   CompoundObject *so = new CompoundObject("non-shared payload");
   CompoundObject **sop = new (CompoundObject *);
   *sop = so;
   return new CompoundObjectProxy(sop);
}

void handleObj(ObjectProxyIfc *iObj)
{
   switch (iObj->type())
   {
      case SimpleProxy: {
         const SimpleObject *anObj = iObj->get<SimpleObject>();
         std::cout << "Handling " << anObj->objName() << std::endl;
      } break;
      case CompoundProxy: {
         CompoundObject *const *objs = iObj->get<CompoundObject *>();
         const CompoundObject *anObj = *objs;
         std::cout << "Handling " << anObj->objName() << "; " << anObj->annotation() << std::endl;
      } break;
   }
}

int main()
{
   // common, adapted methods can be accessed from the base class for
   // adapters, re: name()
   //
   ObjectProxyIfc *ptrOne = oPI();
   std::cout << "First object is " << ptrOne->name() << std::endl;

   // rarely, the client may need access to the data/methods in the
   // wrapped object, which have no counterpart in the common subset
   // implemented by the adapter. For this we go directly to the
   // wrapped object.
   //
   handleObj(ptrOne);

   ObjectProxyIfc *ptrTwo = oPI2();
   std::cout << "Second object is " << ptrTwo->name() << std::endl;
   handleObj(ptrTwo);

   return 0;
}

0 个答案:

没有答案
相关问题