这是使用用于“方法注入”的虚拟继承模式。一个已知的范式? [英] Is this use pattern of virtual inheritance for "method injection" a known paradigm?

查看:97
本文介绍了这是使用用于“方法注入”的虚拟继承模式。一个已知的范式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

昨天,我遇到了这个问题:强制使用不合格的名称值最初,它似乎是一个非常具体的问题与破碎的VC ++行为相关,但在尝试解决它,我偶然发现了一个虚拟继承的使用模式,我没有遇到之前(我会解释它在一个第二,告诉你我的问题)。我发现它很有趣,所以我寻找它的SO和谷歌,但我找不到任何东西。也许,我只是不知道正确的名称(方法注入是我的猜测之一),它实际上是广为人知的。这也是我对群体的问题的一部分:这是常见的使用模式还是另一种已知范例的特殊情况?您是否看到可以通过不同解决方案避免的任何问题/陷阱?

Yesterday, I came across this question: forcing unqualified names to be dependent values Originally, it seemed like a very specific question related to broken VC++ behaviour, but while trying to solve it, I stumbled upon a use pattern of virtual inheritance I hadn't come across before (I will explain it in a second, after telling you the question I have). I found it interesting, so I looked for it on SO and google, but I couldn't find anything. Maybe, I just don't know the right name for it ("method injection" was one of my guesses) and it is actually widely known. This is also part of my question for the community: Is this a common use pattern or a special case of another known paradigm? Do you see any problems/pitfalls that can be avoided by a different solution?

此模式可以解决的问题如下:假设您有一个类 Morph 使用方法 doWork()。在 doWork()中,调用几个函数,其实现应由用户选择(这就是为什么类被调用 Morph )让我们调用那些被称为函数chameleons(因为Morph类不知道他们将在末尾)。实现这一点的一种方法当然是使Morph类的变色龙虚拟方法,因此用户可以从 Morph 中导出并覆盖所选的方法。但是如果用户希望使用不同的组合来选择不同变色龙的实现,该怎么办?然后,对于每个组合,必须定义一个新类。此外,如果有多个 Morph 类的类,其中相同的函数应该是变色龙?用户如何重用她已经实现的替换?

The problem this pattern can solve is the following: Suppose you have a class Morph with a method doWork(). Within doWork(), several functions are called whose implementation is supposed to be selectable by the user (that's why the class is called Morph). Let's call those called functions chameleons (since the Morph class doesn't know what they will be in the end). One way to achieve this would of course be to make the chameleons virtual methods of the Morph class, so the user can derive from Morph and override selected methods. But what if the user is expected to use different combinations for selecting the implementation for different chameleons. Then, for every combination, a new class has to be defined. In addition, what if there are multiple Morph-like classes where the same functions are supposed to be chameleons? How can the user reuse the replacements she already implemented?

对于多个类必须被定义的问题,立即,模板飞跃。用户不能通过传递类作为定义所需实现的模板参数来选择他想要的变色龙实现?也就是说例如 Morph< ReplaceAB> ,它应该有效地替换变色龙 A() B ( in in do(),留下可能的其他变色龙,例如 C $ c>,未触动过。使用C ++ 11和可变参数模板,即使组合也不会有问题: Morph< ReplaceAB,ReplaceC,WhateverMore ...> 模式可以做到(见下面的解释):

As for the "multiple classes have to be defined" problem, immediately, templates leap into one's mind. Can't the user select the chameleon implementations he wants by passing classes as template parameters which define the desired implementation? I.e. something like Morph<ReplaceAB> which should effectively replace the chameleons A() and B() in doWork() with some implementation, leaving the possible other chameleons, e.g., C(), untouched. With C++11 and variadic templates, even the combinations would not be a problem: Morph<ReplaceAB, ReplaceC, WhateverMore...> Well, that's exactly, what this pattern can do (see below for explanation):

#include <iostream>

using namespace std;

// list all chameleons, could also be make some of them
// pure virtual, so a custom implementation is *required*.
struct Chameleons
{
  virtual void A() { cout << "Default A" << endl; }
  virtual void B() { cout << "Default B" << endl; }
  virtual void C() { cout << "Default C" << endl; }
};

// Chameleon implementations for A and B
struct ReplaceAB : virtual Chameleons
{
  virtual void A() { cout << "Alternative A" << endl; }
  virtual void B() { cout << "Alternative B" << endl; }
};

// Chameleon implementation for C
struct ReplaceC : virtual Chameleons
{
  virtual void C() { cout << "Alternative C" << endl; }
};

// A(), B(), C() in this class are made chameleons just by
// inheriting virtually from Chameleons
template <typename... Replace>
struct Morph : virtual Chameleons, Replace...
{
  void doWork() {
    A();
    B();
    C();
    cout << endl;
  }
};

int main()
{
  //default implementations
  Morph<>().doWork();
  //replace A and B
  Morph<ReplaceAB>().doWork();
  //replace C
  Morph<ReplaceC>().doWork();
  //replace A, B and C;
  Morph<ReplaceAB,ReplaceC>().doWork();
}

其输出如下:

Default A
Default B
Default C

Alternative A
Alternative B
Default C

Default A
Default B
Alternative C

Alternative A
Alternative B
Alternative C

只看到这个工作解决方案,上述想法的问题实际上并不那么明显:Could not Morph 只是从指定为模板参数的类派生,所以变色龙 A() B / code>和 C()是从任何 Morph 继承而来的?这实际上是不可能的,因为对变色龙的调用不依赖于模板参数,并且这些非依赖名称不在依赖继承类中查找(如果需要,可以尝试)。这意味着,我们不知何故必须实现变色龙调用绑定到可以被期望的实现替换的东西。

Seeing this working solution only, the problem with the above idea is actually not so obvious: Couldn't Morph just derive from the classes specified as template parameters, so the chameleons A(), B() and C() are just taken from whatever Morph inherits from? This is actually not possible, because the calls to the chameleons do not depend on the template parameters, and such non-dependent names are not looked up in dependent inherited classes (try it, if you want). This means, we somehow have to achieve that the chameleon calls bind to something that can later be replaced by the desired implementation.

这是虚拟继承进来的地方:letting Morph 继承 Chameleons (不依赖于模板参数),非限定变色龙调用 doWork()绑定到 Chameleons 中的虚拟函数。因为 Morph 替换类实际上从 Chameleons 在任何 Morph 对象中只有一个 Chameleons 对象,并且将调度虚函数调用在运行时到大多数派生类中的实现,我们通过模板化的继承走私。所以,虽然在 doWork()中的无限制的变色龙名称不能在编译时解析为所需的实现(根据标准),它们仍然可以由层调用通过虚拟基类的间接。有趣,是吗? (除非你告诉我这种方式更容易用不同的方式,或者模式是广为人知的。)

That's where the virtual inheritance comes in: By letting Morph inherit from Chameleons (non-dependent on the template parameters), the unqualified chameleon calls in doWork() bind to the virtual functions in Chameleons. Because Morph and the Replacement classes inherit virtually from Chameleons, there will only be a single Chameleons object in any Morph object, and the virtual function calls will be dispatched at run-time to the implementation in the most derived class, which we "smuggle in" through the templated inheritance. So, although the unqualified chameleon names in doWork() cannot be resolved to the desired implementation at compile time (in accordance with the standard), they can still be called by a layer of indirection through a virtual base class. Funny, huh? (Unless you tell me this is much easier to do in a different way or the pattern is widely known.)

推荐答案

工作正常。虚拟继承避免歧义错误。 Variadic模板带来了优雅的实例化语法。而不是类似:

Your solution works fine. Virtual inheritance avoids ambiguity errors. Variadic template brings elegant instantiation syntax. Instead of something like:

 class M1 : public ReplaceAB, ReplaceC {} i1;
 i1.doWork();

您只有一行:

Morph<ReplaceAB, ReplaceC>().doWork();

从我的角度来看,建议的模式不常见。同时,这是真的新吗?嗯,有数百万和几百万行代码...有人使用类似的东西的机会不是零。很可能你永远不会知道这一点。

From my point of view the proposed pattern is not common. A the same time, is this something really new? Well, there are millions and millions lines of code... The chance that somebody used something similar is not zero at all. Most likely you will never know this for sure.

这篇关于这是使用用于“方法注入”的虚拟继承模式。一个已知的范式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆