gpt4 book ai didi

c++ - "method injection"的这种虚拟继承使用模式是已知范例吗?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:45:47 26 4
gpt4 key购买 nike

昨天,我遇到了这个问题:forcing unqualified names to be dependent values最初,这似乎是一个与破坏 VC++ 行为相关的非常具体的问题,但是在尝试解决它时,我偶然发现了一种我以前从未遇到过的虚拟继承的使用模式(我会在告诉你之后解释一下)我的问题)。我发现它很有趣,所以我在 SO 和 google 上寻找它,但我找不到任何东西。也许,我只是不知道它的正确名称(“方法注入(inject)”是我的猜测之一)而且它实际上广为人知。这也是我向社区提出的问题的一部分:这是一种常见的使用模式还是另一种已知范式的特例?您是否看到可以通过不同的解决方案避免的任何问题/陷阱?

这个模式可以解决的问题如下:假设你有一个类 Morph使用方法 doWork() .内doWork() , 几个函数被调用,它们的实现应该是用户可以选择的(这就是为什么这个类被称为 Morph )。让我们称这些被调用的函数为变色龙(因为 Morph 类不知道它们最终会是什么)。实现这一点的一种方法当然是使 Morph 类的变色龙虚拟方法,因此用户可以从 Morph 派生。并覆盖选定的方法。但是,如果希望用户使用不同的组合来为不同的变色龙选择实现呢?然后,对于每个组合,都必须定义一个新类。另外,如果有多个Morph怎么办? -类似的类,其中相同的功能应该是变色龙?用户如何重用她已经实现的替换?

对于“必须定义多个类”的问题,模板立即跃入脑海。用户不能通过将类作为定义所需实现的模板参数来选择他想要的变色龙实现吗? IE。类似 Morph<ReplaceAB>这应该有效地取代变色龙 A()B()doWork()通过一些实现,留下可能的其他变色龙,例如,C() ,未动。使用 C++11 和可变参数模板,即使组合也不成问题:Morph<ReplaceAB, ReplaceC, WhateverMore...>嗯,这正是这种模式可以做的事情(见下文解释):

#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

只看到这个可行的解决方案,上述想法的问题其实并不那么明显:Couldt Morph只是从指定为模板参数的类派生,所以变色龙 A() , B()C()只是取自 Morph继承自?这实际上是不可能的,因为对变色龙的调用不依赖于模板参数,并且在依赖继承的类中不会查找此类非依赖名称(如果需要,请尝试)。这意味着,我们必须以某种方式实现变色龙调用绑定(bind)到稍后可以由所需实现替换的内容。

这就是虚拟继承的用武之地:通过让 Morph继承自 Chameleons (不依赖于模板参数),不合格的变色龙调用 doWork()绑定(bind)到 Chameleons 中的虚函数.因为 MorphReplacement类实际上继承自 Chameleons ,只会有一个 Chameleons任何对象中的对象 Morph对象,并且虚函数调用将在运行时分派(dispatch)到最派生类中的实现,我们通过模板化继承“走私”。所以,虽然 doWork()中不合格的变色龙名称无法在编译时解析为所需的实现(按照标准),它们仍然可以通过虚拟基类由间接层调用。有趣吧? (除非你告诉我,以不同的方式这样做会容易得多,或者这种模式广为人知。)

最佳答案

您的解决方案工作正常。虚拟继承避免了歧义错误。可变模板带来优雅的实例化语法。而不是像:

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

你只有一行:
Morph<ReplaceAB, ReplaceC>().doWork();

在我看来,提议的模式并不常见。同时,这真的是新东西吗?嗯,有数百万行代码......有人使用类似的东西的可能性根本不是零。很可能你永远不会知道这一点。

关于c++ - "method injection"的这种虚拟继承使用模式是已知范例吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24319185/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com