【问题标题】:C++ Visitor Pattern and PolymorphismC++ 访问者模式和多态性
【发布时间】:2016-08-07 06:01:28
【问题描述】:

以下代码是我在项目中实现的 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 对象)

【问题讨论】:

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


    【解决方案1】:

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

    void accept(AVisitor *visitor) override;
    

    那么,我们来看看AVisitor的接口。它有

    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;
    

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

    【讨论】:

    • ActualVisitor 类重写了 visit(A*) 和 visit(B*) 方法,所以由于接受的签名是接受(AVisitor * visitor),通过多态性,我希望调用访问者-> visit(B*) 选择正确的方法。我错过了什么?
    • 你的代码不是引用ActualVisitor的接口,而是引用AVisitor的接口。 ActualVisitor 中的 重载 虚函数不是 覆盖 AVisitor 中的方法。
    • 我明白了,你是对的。那么如果ActualVisitor没有覆盖visitor(B*),就意味着我有一个非抽象类没有实现所有的纯虚函数(这里是visit(A*)和visit(B*))?还是visit(A*) 是visit(A*) 和visit(B*) 纯虚函数的实现?
    • 如果它不覆盖visitor(B*),你确实会遇到构建错误。
    【解决方案2】:

    您错误地实现了访问者。这是正确的方法:

    class AVisitor {
    public:
        virtual void visit(class A *) = 0;
        virtual void visit(class B *) = 0;
        // virtual void visit(class C *) = 0; etc
        // a separate function for every class in your hierarchy
    };
    

    然后

    class ActualVisitor : public Visitor ...
    

    不需要ExtendedVisitor

    是的,AVisitor 必须了解层次结构中的每个类。这是这种模式的主要缺点。

    【讨论】:

      猜你喜欢
      • 2016-09-10
      • 2012-03-11
      • 1970-01-01
      • 1970-01-01
      • 2022-07-10
      • 1970-01-01
      • 2011-06-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多