及时派生

时间:2009-12-17 11:51:16

标签: c++ idioms mixins type-erasure crtp

我过去常常使用过几次不太常见的C ++习语。我似乎无法记住它是否有一个通常使用的名称来描述它。

它与mixinsCRTPtype-erasure有些相关,但并非具体与此相关。

当您想要向类中添加一些实现时,会发现问题,但您不希望将放在类或它派生的任何类中。这样做的一个原因可能是类可能是继承层次结构的一部分,其中实现应该只发生一次。

暂时搁置一些问题,例如层次结构是否应该具有具体的非叶类,或者在某些情况下是否可以选择虚拟继承,我知道在模板类中提供实现的一种解决方案派生自其模板参数。然后,这允许您在创建实例时使用该模板,但之后只能通过指针使用该对象或引用其中一个基础(这是松散意义上的类型擦除的地方)。

一个例子可能是你有一个侵入性引用计数。你的所有类都来自一个引用计数接口,但是你只希望引用计数本身和引用计数方法的实现出现一次,所以你将它们放在派生模板中 - 让我们称之为ImplementsRC<T>。现在你可以像这样创建一个实例:

ConcreteClass* concrete = new ImplementsRC<ConcreteClass>();

我正在审视由多个模板化重载等构成的转发构造函数等。

所以,希望我已经明确了成语是什么。现在回到我的问题 - 这个成语是否有一个被接受的,或者至少是一般使用的名称?

9 个答案:

答案 0 :(得分:3)

这是一个有趣的想法。但是我不会在这里给你一个已经建立的模式的名称,相反,我会解释(有些)为什么我不认为它已经有了。

它做了什么?

这是避免恐惧钻石继承的一种非常好的方法。

由于显然对方法的目的存在一些混淆,让我详细说明为什么我认为这是它的目的:

class RefCounted
{
  virtual void addReference() = 0;
  virtual void removeReference() = 0;
};

class B: public RefCounted {};
class C: public RefCounted {};

class Diamond: public B, public C {};

现在,我们遇到了一个问题。如果我们将RefCounted的实现放在这个类中,它就变成了基类而不是接口,因此我们必须使用虚拟继承,否则数据成员将被复制(存在于B和C中) )。

因此,我们的想法是将实施推迟到最后一刻。

优点:

  • 无需尝试再次猜测B或C的使用:那里不需要虚拟继承。
  • 如果您忘记添加实现,编译器会很好地提醒您,所以不必担心。

不方便:

  • 把负担放在客户端上:你最好有一个工厂来创建你的对象,特别是因为一个对象可以实现各种接口!请注意,这可以通过模板元编程(或多或少)自动执行,也可以由类作者简单提供。

提供示例:

// d.h
class D: public B, public C
{
public:
  typedef ImplementRC<D> concrete_type;
  static concrete_type Build(int, int); // Named Constructor idiom

private:
  D(int,int);
}; // class D

// main.cpp
D::concrete_type myD = D::Build(1,2);

那叫什么名字?

我想不出任何与此完全匹配的东西。 Bridge和Decorator已被提及,但这是非常特殊的,实际上并不是面向OO(例如,由于你没有多重继承,它不会在Java中发生),所以我怀疑这个术语是否会被发现在GoF的书中。

此外,它不是真正的CRTP,因为CRTP中存在一种循环(基础知道它的派生类),这不会发生在这里&gt;我们确实是严格线性的!

然后,它肯定不是Pimpl成语,它建议将实现隐藏在远离客户端的同时使用模板实现它只是把它抛到脑后! (模板可以使用Pimpl作为内部细节)

我谦虚地建议 jiti Just In Time Implementation ,它以某种方式模仿标题,但更接近我认为的点,这里的推导只​​是一个工具而不是一个目标。

无论如何有趣的想法。

答案 1 :(得分:1)

我不确定它有一个名字,因为gf建议它看起来有点像桥模式。这几乎就像是你对基类的功能挂钩。

我建议使用pimp成语的新名称。因为你正在拉你的基类;)

答案 2 :(得分:1)

您在寻找Decorator pattern吗?

基本上,装饰器是一个包含另一个对象并扩展某些方法功能的对象。然后将方法调用转发到封闭的方法。

答案 3 :(得分:1)

这是一个混合

答案 4 :(得分:1)

我肯定会认为这是一个混合,就像布鲁斯·埃克尔(http://www.artima.com/weblogs/viewpost.jsp?thread=132988)一样。

在我看来,使其成为混合物的一个原因是它仍然是单一继承,这与使用MI实现类似的东西不同。

答案 5 :(得分:1)

查看您的引用计数示例,您可能会对CComObject&lt;&gt;进行调查。这是ATL包含的几个模板类之一,用于提供IUnknown的实现。它还使用策略类来改变行为。当然,尝试Google 关于 CComObject概念的信噪比非常低,因为它无处不在。这篇MSDN文章可能会为您提供更多“关键字”,以帮助您进行任何搜索。

http://msdn.microsoft.com/en-us/library/c43h4867(VS.80).aspx

[注意:要明确 - 我不是建议他使用 CComObject,我建议它是同一概念的另一个流行的例子,因此可能在模式书中被引用或者文章]

答案 6 :(得分:0)

看起来像Pimpl idiom?也许以不寻常的方式使用。

答案 7 :(得分:0)

我不确定但它是“空成员c ++优化”吗?

使用类模板私有继承实现此类行为。

Scott Meyer撰写的杂志文章“用C ++计算对象”进行了解释。

答案 8 :(得分:0)

回答我自己的问题。疯狂的第一个迹象? - 在此之前没有几个迹象; - )

无论如何,自从我最初发布以来,我或多或少是一个不同的人。

我发现我确定了这个名字, mixover 。我发现这非常合适,可以被认为是mixin的改进,而不是专属于更一般的概念。

我最近一直在使用它们,所以我想我会回来更新这个帖子。