8

有一个不太常见的 C++ 习惯用法,过去我用过几次效果很好。我似乎不记得它是否有一个常用的名称来描述它。

它与mixinsCRTPtype-erasure有点相关,但与这些东西无关。

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

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

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

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

我正在掩盖诸如由多个模板化重载形成的转发构造函数等内容。

所以,希望我已经说清楚了这个成语是什么。现在回到我的问题 - 这个成语是否有一个公认的或至少普遍使用的名称?

4

9 回答 9

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 {};

现在,我们这里有一个问题。如果我们把RefCountedright 的实现放在这个类中,它就变成了基类而不是接口,因此我们必须使用虚拟继承,否则数据成员将重复(在 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 中存在一种循环(基础知道它的派生类)在这里不会发生 > 我们确实是严格线性的!

然后,它肯定不是 Pimpl 惯用语,它建议将实现隐藏在客户端之外,而使用模板来实现只是把它扔到它的脸上!(模板可以使用 Pimpl 作为内部细节)

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

无论如何,有趣的想法。

于 2009-12-17T18:18:57.540 回答
1

我不确定它有名字,因为 gf 建议它看起来有点像桥模式。这几乎就像您将功能连接到基类一样。

我为此建议一个新名称,皮条客成语。当你拉皮条你的基类;)

于 2009-12-17T12:49:09.223 回答
1

您在寻找 装饰器模式吗?

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

于 2009-12-17T13:49:28.177 回答
1

这是一个混音

于 2009-12-17T13:55:48.323 回答
1

我肯定会认为这是一个 mixin,Bruce Eckel ( http://www.artima.com/weblogs/viewpost.jsp?thread=132988 ) 也是如此。

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

于 2009-12-17T20:45:46.623 回答
1

查看您的引用计数示例,您可能会对 CComObject<> 感到高兴,它是 ATL 包含的几个模板类之一,用于提供 IUnknown 的实现。它还使用策略类来改变行为。自然地,谷歌关于 CComObject 概念的信噪比非常低,因为它是如此无处不在。这篇 MSDN 文章可能会为您提供更多“关键字”来帮助您进行任何搜索。

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

[注意:为了清楚起见——我并不是建议他使用CComObject,我建议它是同一概念的另一个流行示例,因此可能已在模式书或文章中被引用]

于 2009-12-18T13:54:15.333 回答
0

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

于 2009-12-17T12:05:12.740 回答
0

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

这种行为是使用类模板私有继承来实现的。

Scott Meyer在名为“Counting Objects in C++”的杂志文章中对此进行了解释。

于 2009-12-17T13:01:43.820 回答
0

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

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

我发现我已经确定了这个名字,mixover。我发现这非常适合并且可以被认为是对 mixin 的改进,而不是对更一般的概念进行排他性。

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

于 2011-06-10T08:23:36.570 回答