用 C++ 设计包装器 Class

Design of a Wrapper Class in C++

我必须使用界面非常笨拙的旧 class。因为我不能改变它并且依赖它,所以我想构建一个包装器,提供一个干净的界面。假设我有一个 class ClumsyClass。基本上,我有三种方法:

1.参考会员

    Class Wrapper {
      public:
        Wrapper (ClumsyClass& clumsyClass)
          : m_clumsyClass(clumsyClass)
        { }

        int getSmth() {
          return m_clumsyClass.getSmth();
        }

        private:
          ClumsyClass& m_clumsyClass;
}

2。指针成员

    Class Wrapper {
      public:
        Wrapper (ClumsyClass* clumsyClass)
          : m_clumsyClass(clumsyClass)
        { }

        int getSmth() {
          return m_clumsyClass->getSmth();
        }

        private:
          ClumsyClass* m_clumsyClass;
}

3。继承

    Class Wrapper : public ClumsyClass {
    ...
}

哪种方法是 "cleanest" 实现包装器的方法?我更喜欢第三个,但是当我已经有一个 ClumsyClass 对象然后创建一个 Wrapper 对象(复制构造函数)时,将需要更多内存(因为在我的情况下需要原始 class 的实例)。

我会避免使用 3,因为它无法封装 ClumsyClassWrapper 的用户可以有意或无意地直接访问 ClumsyClass 的 "clumsy" 界面,这是您试图避免的。更喜欢组合而不是继承。

1. 和 2. 之间的区别很小。使用引用成员会降低包装器的灵活性。 class 不可分配,您不能重新设置引用并将其替换为 ClumsyClass 的不同实例,并且成员不能为空。根据您的要求,这些可能是好事也可能是坏事。

但如评论中所述,默认选择可能应该是将 ClumsyClass 作为 Wrapper 的按值成员:

class Wrapper {
  public:
    // possible constructors
    //Wrapper(const ClumsyClass& cc) : m_clumsyClass(cc) {} // copy 
    //Wrapper(ClumsyClass&& cc) : m_clumsyClass(std::move(cc)) {}  // move 
    int getSmth() { return m_clumsyClass.getSmth(); }

  private:
    ClumsyClass m_clumsyClass;
};

在您的特定用例中这可能不可行或不可取的原因有很多,然后您可以回退到选项 1 或 2。决定主要取决于所有权。 Wrapper "own" 应该 ClumsyClass 还是 ClumsyClass 的实例的生命周期在 Wrapper 之外?

使用直接成员的一个潜在缺点是您不能再将 ClumsyClass 的实现隐藏在前向声明后面,因此您会丢失一些 ClumsyClass 的封装。值得注意的是,解决这个问题的一种方法是提取出Wrapper继承的抽象基class"interface"。类似于:

class IWrapper {
  public:
    virtual ~IWrapper() {}
    virtual int getSmth() = 0;
};

这可能会提供额外的好处,例如可测试性。

从你提到的限制看来,这可能是一个可行的方法:

使用您喜欢的方法创建接口

struct IMyMethods 
{
  virtual int getOther() = 0;
  ...
  virtual ~IMyMethods() {};
};

现在创建一个新的 class 派生自您的 class 和您要在 class 上使用的接口,在其中添加接口

的实现
class MyAgileClass : public ClumsyClass, IMyMethods
{
public:
   MyAgileClass(/*same args as for ClumsyClass*/)
   {}
   ~MyAgileClass() 
   {}

   virtual int getOther() 
   {
     return getSmth(); // clumsy class function
   }
   ...
};

您现在可以直接或通过简化界面访问 ClumsyClass