gpt4 book ai didi

c++ - 从对基类的引用调用更具体的重载函数

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:50:41 24 4
gpt4 key购买 nike

首先,对于隐晦的标题,抱歉,这并不容易解释。

我想做的是使用重载函数在 C++ 中实现访问者模式。这是我的情况:

  1. 我有一组解析器。每个解析器返回一个特定派生类型的 Element。基本上,我最终得到了 Element 的多态集合,它们都实现了 visit(Visitor&) 函数。
  2. 我有一些分析器(Visitor)。每个访问者只对几个特定的​​ Element 派生类感兴趣。
  3. Visitor 的基类有一个空的 visit(Element&) 实现,它接收一个 Element 引用作为参数。
  4. 每个 Visitor 派生类为其感兴趣的特定元素类型实现 visit 函数。也就是说,我有一个 visit(DerivedElement&) DerivedVisitor 类中的重载函数。
  5. 当调用 accept(Visitor& v) { v.visit(*this); },被调用的函数应该是更具体的函数。也就是说,如果 v 是一个 DerivedVisitor 并且 accept 是在一个 DerivedElement 中实现的,我想要这个函数visit(DerivedElement&) 被调用。

一些示例代码:

#include <iostream>

using namespace std;

class Visitor
{
public:
virtual void visit(class BaseElement& e);
};

class BaseElement
{
public:
virtual void accept(Visitor &v)
{
cout << "accept on BaseElement" << endl;
v.visit(*this);
}

virtual void doThings()
{
cout << "doThings on BaseElement" << endl;
}
};

void Visitor::visit(BaseElement& e)
{
cout << "visit on Visitor" << endl;
e.doThings();
}

class DerivedElement : public BaseElement
{
public:
virtual void accept(Visitor &v)
{
cout << "accept on DerivedElement" << endl;
v.visit(*this);
}

virtual void doThings()
{
cout << "doThings on DerivedElement" << endl;
}
};

class DerivedVisitor : public Visitor
{
public:
void visit(BaseElement& e)
{
cout << "visit-BaseElement on DerivedVisitor" << endl;
e.doThings();
}

void visit(DerivedElement &e)
{
cout << "visit-DerivedElement on DerivedVisitor" << endl;
e.doThings();
}
};

int main(int argc, char** argv)
{
BaseElement eBase;
DerivedElement eDeriv;
BaseElement& eDerivAsBase = eDeriv;
Visitor vBase;
DerivedVisitor vDeriv;

cout << "Visiting a BaseElement with the base visitor:" << endl;
eBase.accept(vBase);
cout << endl << "Visiting a BaseElement with the derived visitor:" << endl;
eBase.accept(vDeriv);

cout << endl << "Visiting Base and Derived elements with the derived visitor" << endl;
eBase.accept(vDeriv);
eDeriv.accept(vDeriv);

cout << endl << "Visiting Base element as Derived reference" << endl;
eDerivAsBase.accept(vBase);
eDerivAsBase.accept(vDeriv);

}

这是输出

Visiting a BaseElement with the base visitor:
accept on BaseElement
visit on Visitor
doThings on BaseElement

Visiting a BaseElement with the derived visitor:
accept on BaseElement
visit-BaseElement on DerivedVisitor
doThings on BaseElement

Visiting Base and Derived elements with the derived visitor
accept on BaseElement
visit-BaseElement on DerivedVisitor
doThings on BaseElement
accept on DerivedElement
visit-BaseElement on DerivedVisitor (!)
doThings on DerivedElement

Visiting Base element as Derived reference
accept on DerivedElement
visit on Visitor
doThings on DerivedElement
accept on DerivedElement
visit-BaseElement on DerivedVisitor (!)
doThings on DerivedElement

标有(!) 的行是我想要更改的行。这些行应该是“DerivedVisitor 上的 visit-DerivedElement”。

这可能吗?看到 C++ 没有实现 multiple dispatch这似乎很难,我可能在要求不可能的事情。但是,我真的很想看看我有哪些替代方案,因为为我拥有的每个派生元素编写空的 accept(DerivedElementN&) 方法似乎不是最佳选择。

最佳答案

您在这里进行了大量的动态间接寻址。因此,您也需要以这种方式构建访问者。

 struct BaseVisitor {
std::unordered_map<std::type_info, std::function<void(BaseElement&)>> types;
template<typename D, typename F> void AddOverload(F f) {
types[typeid(D)] = [=](BaseElement& elem) {
f(static_cast<D&>(elem));
};
}
virtual void visit(BaseElement& elem) {
if (types.find(typeid(elem)) != types.end())
types[typeid(elem)](elem);
}
};
struct DerivedVisitor : BaseVisitor {
DerivedVisitor() {
AddOverload<DerivedElement>([](DerivedElement& e) {
});
//... etc
}
};

核心问题是,只要您需要动态间接寻址,就不能使用模板。您所能做的就是在垃圾邮件 dynamic_cast 上提供额外的类型安全性和便利性(以及潜在的速度)。

作为一个简短的说明,上面的代码可能无法完全正常工作 - typeid 到引用或 const 或类似的东西可能会导致类型查找失败的一些乐趣应该会成功。

如果它对您很重要,可以应用其他技术来消除该限制,但您可能想坚持使用 dynamic_cast,因为它很有趣但很糟糕。

关于c++ - 从对基类的引用调用更具体的重载函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29565524/

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