C++ 访问者模式和多态性

标签 c++ polymorphism abstract-class virtual-functions

以下代码是我在我的项目中实现的 VisitorPattern 的简化版本。

#include <iostream>
class AVisitor {
public:
    virtual void visit(class A *) = 0;
};

class ExtendedVisitor : public AVisitor {
public:
    virtual void visit(class B *) = 0;
};

class A {
public:
    virtual void accept(AVisitor *visitor) {
        std::cout << "Call accept of A" << std::endl;
        visitor->visit(this);
    }
};

class B : public A {
public:
    void accept(AVisitor *visitor) override {
        std::cout << "Call accept of B" << std::endl;
        B *just_this = this;
        visitor->visit(just_this);  //why this calls to visit(A*)
        visitor->visit((B*) just_this); //useless casting 
    }
};

class ActualVisitor : public ExtendedVisitor {
public:
    void visit(A *x) override {
        std::cout << "Call visit on A*" << std::endl;
    }
    void visit(B *x) override {
        std::cout << "Never called" << std::endl;
    }
};

int main() {
    ActualVisitor visitor;
    A *a = new B();
    a->accept(&visitor);
}

我不明白为什么B类的accept方法调用的是visitor(A*)方法而不是visitor(B*)方法。主要功能打印

Call accept of B
Call visit on A*
Call visit on A*

相反,以下代码的行为符合我的预期:

#include <iostream>

class AVisitor {
public:
    virtual void visit(class A *) = 0;
    virtual void visit(class B *) = 0;
};

class A {
public:
    virtual void accept(AVisitor *visitor) {
        std::cout << "Call accept of A" << std::endl;
        visitor->visit(this);
   }
};

class B : public A {
public:
    void accept(AVisitor *visitor) override {
        std::cout << "Call accept of B" << std::endl;
        B *just_this = this;
        visitor->visit(just_this);  //now it works
        visitor->visit((B*) just_this);  
    }
};

class ActualVisitor : public AVisitor {
public:
    void visit(A *x) override {
        std::cout << "Call visit on A*" << std::endl;
    }
    void visit(B *x) override {
        std::cout << "Call visit on B*" << std::endl;
    }
};

int main() {
    ActualVisitor visitor;
    A *a = new B();
    a->accept(&visitor);
}

它现在打印:

Call accept of B
Call visit on B*
Call visit on B*

问题似乎是 AVisitor 类的继承问题。我想知道为什么会发生这种情况以及设计具有“专门”访问者的 VisitorPattern 的正确方法是什么(这里 ExtendedVisitor 也可以访问 B 对象)

最佳答案

您的 B::accept 具有以下签名:

void accept(AVisitor *visitor) override;

那么,让我们检查一下AVisitor 的接口(interface)。它有

virtual void visit(class A *) = 0;

这就是它的全部(在您的第一个版本中)。 ExtendedVisitor 确实有

virtual void visit(class B *) = 0;

但是不会覆盖AVisitor 中的方法。事实上,您的第二个版本可以帮助您了解原因。由于

virtual void visit(class A *) = 0;
virtual void visit(class B *) = 0;

可以一起驻留在同一个类中(它们在您的第二个版本中是重载),那么在这方面它们是不同的方法。

关于C++ 访问者模式和多态性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38811377/

相关文章:

C++ 为什么链接器看不到我的文件?

delphi - Spring 框架中是否有内置的方法可以使多态容器的使用变得更容易?

python - Django - 如何以子类形式而不是父类形式返回 QuerySet 中的所有对象?

c++ - 在 C++ 中使用 TetGen 加载网格文件

c++ - Thread sanitizer 给出 "function race"的假阴性

c++ - 多态调用的成本 - C++

java - 通过继承改进程序

java - 具有所有具体方法的普通类和具有所有具体方法的抽象类有什么区别

jakarta-ee - IDEA错误 "Managed bean must be a concrete class, or is annotated with @Decorator"

c++ - 使用 CppAD 时,IPOPT 不服从约束但不记录违规