gpt4 book ai didi

c++ - 重载和 this 指针

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:11:31 25 4
gpt4 key购买 nike

这个问题更像是理论问题。

前言。访客模式:

class Visitor
{
public:
virtual void VisitElementA(const ElementA& obj) = 0;
virtual void VisitElementB(const ElementB& obj) = 0;
};

class Element
{
public:
virtual void Accept(Visitor& visitor) = 0;
};

class ElementA : public Element
{
public:
void Accept(Visitor& visitor) override { visitor.VisitElementA(*this); }
};

class ElementB : public Element
{
public:
void Accept(Visitor& visitor) override { visitor.VisitElementB(*this); }
};

这个 VisitElementA(const ElementA& obj) 看起来有点难看,所以使用重载我们可以这样重写它:

class Visitor
{
public:
virtual void Visit(const ElementA& obj) = 0;
virtual void Visit(const ElementB& obj) = 0;
};

现在我们在 ElementA 和 ElementB 中有两个相同的 Accept 方法实现:

void Accept(Visitor& visitor) override { visitor.Visit(*this); }

并且必须将此类代码添加到 ElementC、ElementD 等(如果有)

问题是:如何避免这种重复?

将 Accept 实现放置在 Element 类(或其他中间类)中的简单解决方案将不起作用,因为 this 指针将指向对象作为类 Element 的对象,而不是 ElementA 或ElementB,因此在最好的情况下我们会得到编译错误,甚至是错误的行为(如果 Element 有一些重载的 Visit 方法)。

据我了解,问题在于试图混合编译时和运行时功能。但可能存在一些基于模板的解决方案或新的 C++11 功能,或其他什么?

请注意:如果您不提供带有“宏魔法”的解决方案,我将不胜感激:)。

最佳答案

您可以使用 CRTP模式。

转换类 Element进入一个模板类,该模板类将派生类型作为类型参数。然后您可以在调用访问者之前向下转换为派生类型:

template <typename Derived>
class Element
{
public:
void Accept(Visitor& visitor) { visitor.Visit(*static_cast<Derived*>(this)); }
};

最后,每个具体元素都派生自Element这样:

class ElementA : public Element<ElementA>
{
};

另请注意 Accept(Visitor&)不再需要虚拟。

更新:以下是 quetzalcoatl 指出的问题的解决方案:

class ElementC : public Element<ElementC>, public ElementA
{
public:
using Element<ElementC>::Accept;
};

通过using声明,ElementC带来 Accept name 进入其范围,因此,基类中的名称被隐藏。然而,这AcceptElement<ElementC>::Accept而且,在实践中,只有 ElementA::Accept是隐藏的。

关于c++ - 重载和 this 指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15584627/

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