通过隐式类型转换模拟接口

时间:2015-07-29 17:26:30

标签: c++ implicit-conversion facade

假设我有几个类A1A2A3,其数据可以存储在同一个POD数据结构D中。这些类在如何管理数据方面不同,例如,在哪里分配动态数据结构。从语义上讲,它们代表了所有相同类型的数据。

我的一个A?类旨在成为D的包装器。它可以基于现有的D构建而不复制它。

现在我想以统一的方式实现对所有A?类的读访问。我不想使用虚方法,也不想模板化使用A?类的所有代码。

以下是合理的设计吗?

这种模式有名字吗? (门面?)

有没有明显的陷阱?

/* in practice, D is large or should not be copied for other reasons */
struct D { int * mymember; }

struct ACRef {
   ACRef (D const & d) : m_dataref (&d) { }
   /* operations for A-like classes */
   int getMyMember () const { return *(m_dataref->mymember); }
private:
   D const * m_dataref;
};

struct A1 {
   /* A1 stuff, manages m_data.mymember in a particular way */

   // implicit conversion to ACRef possible
   // kind of "is a" relationship: an A1 "is an" ACRef
   operator ACRef () { return ACRef {this->m_data}; }
private:
   D m_data;
};

struct A2 {
   explicit A2 (D & d) : m_data (&d) { }

   /* A2 stuff, manages m_data.mymember in a particular way */

   // implicit conversion to ACRef possible
   // kind of "is a" relationship: an A2 "is an" ACRef
   operator ACRef () { return ACRef {*(this->m_data)}; }
private:
   D * m_data;
};

/* A3 defined similar to A1 */

/* function that should operate on A?'s */
int printMyMember (ACRef a) {
   std::cout << a.getMyMember () << std::endl;
}

A1 a1;
A2 a2;
// ...
printMyMember (a1);
printMyMember (a2);    

3 个答案:

答案 0 :(得分:2)

我用这种方法看到的唯一缺点是你最终得到了隐含地共享状态的多个对象。所以例如按值传递ACRef并不具有典型含义。但只要您只允许通过ACRef进行读取访问,它就不是一个大问题 如果代理类型最终在与原始对象不同的线程中,那么你必须非常友好。

答案 1 :(得分:0)

我无法看到你的方法有任何明显错误,但有智慧的人告诉我要避免隐式类型转换,所以这让我有点紧张。每当你利用&#34; is-a&#34;时,有些东西都会产生新的物体。关系。

表示&#34; is-a&#34;更为惯用的方式。关系就是使用继承。

为了满足您对ACRef的要求,我们可以使用Base-from-Member成语:

struct D { int member; };

class ACRef {
  const D *data_ref;
 public:
  ACRef(const D &data) : data_ref(&data){}
  int getMember() const { return data_ref->member; }   
};

struct BaseA {
  D data;
  BaseA() : data({0}){}
};

class A1 : protected BaseA, public ACRef {
 public:
  A1() : ACRef(data){}
};

class A2 : protected BaseA, public ACRef {
 public:
  A2() : ACRef(data){}    
};

void printMyMember(const ACRef& a) {
  std::cout << a.getMember() << "\n";
}

int main() {
  A1 a1;
  printMyMember(a1);

  D d = {1};
  ACRef acref(d);
  printMyMember(d);
}

答案 2 :(得分:0)

我认为你不能依赖offsetof(m_data)保持一致(你的例子混合了完整的成员和指针)

为了获得保证的行为,您需要一个定义常见行为的基类。

class Abase{ protected D* m_data;...}

只有这样,演员才能安全地从A *到Abase *(想象vtable被添加到支持析构函数,rtti)为某些A