使用访问者模式检查派生类类型?

时间:2017-08-08 15:08:29

标签: c++ inheritance dynamic-cast visitor-pattern

我正在使用访问者模式来处理许多不同的AST问题,结果证明它工作得非常好。例如,我用它来检查静态类型。这在查找确切类型时效果很好,但它不适用于派生类。即如果我们从Derived继承Base,则询问Derived对象是Base是否失败。

考虑以下C ++代码:

#include <iostream>
#include <functional>
#include <memory>

using namespace std;

class Base;
class Derived;

class Visitor {
public:
    virtual void visit(Base& object) = 0;
    virtual void visit(Derived& object) = 0;
};

class EmptyVisitor : public Visitor {
public:
    virtual void visit(Base& object) override {}
    virtual void visit(Derived& object) override {}
};

template <class TYPE> class LogicVisitor : public EmptyVisitor {
public:
    LogicVisitor(function<void(TYPE&)> logic) : EmptyVisitor(), logic(logic) {}
    virtual void visit(TYPE& object) override { logic(object); }
private:
    function<void(TYPE&)> logic;
};

class Base {
public:
    virtual void accept(Visitor* visitor) {
        visitor->visit(*this);
    }
};

class Derived : public Base {
public:
    virtual void accept(Visitor* visitor) override {
        visitor->visit(*this);
    }
};

template <class TYPE> bool is_type(shared_ptr<Base> base)
{
    bool is_type = false;
    LogicVisitor<TYPE> logic_visitor([&](TYPE& object) {
        is_type = true;
    });
    base->accept((Visitor*)&logic_visitor);
    return is_type;
}

int main() {
    auto base = make_shared<Base>();
    auto derived = make_shared<Derived>();
    cout << "is_type<Base>(base) = " << (is_type<Base>(base) ? "true" : "false") << endl;
    cout << "is_type<Derived>(base) = " << (is_type<Derived>(base) ? "true" : "false") << endl;
    cout << "is_type<Base>(derived) = " << (is_type<Base>(derived) ? "true" : "false") << endl;
    cout << "is_type<Derived>(derived) = " << (is_type<Derived>(derived) ? "true" : "false") << endl;
    return 0;
}

按预期输出 以下结果:

is_type<Base>(base) = true
is_type<Derived>(base) = false
is_type<Base>(derived) = false
is_type<Derived>(derived) = true

虽然这对于检索对象的静态类型很有帮助,但如果我希望is_type<Base>(derived)返回true而不是false,那么如何解决这个问题,以便我可以有效地检查类遗产?这在C ++中是否可行?

1 个答案:

答案 0 :(得分:3)

你做不到。原因是重载决策(和您的设计模式)。每位访问者都有两次重载,一次针对Base&,另一位针对Derived&LogicVisitor使用作为模板参数传递的类型覆盖该函数,因此对于Base,它将覆盖void visit(Base&)

您希望它替换void visit(Derived&) Base而不是Base。但这需要访问者找到源自std::is_base_of的每个类,这在目前是不可能的。

您可以改为使用template<typename T, typename U> constexpr bool is_type(std::shared_ptr<U>) { return std::is_base_of_v<std::decay_t<T>, std::decay_t<U>>; }

package com.vehicle.model;

import java.io.Serializable;
import javax.persistence.*;
import java.math.BigDecimal;


/**
 * The persistent class for the "Vehicles" database table.
 * 
 */
@Entity
@Table(name="\"Vehicles\"")
@NamedQuery(name="Vehicle.findAll", query="SELECT v FROM Vehicle v")
public class Vehicle implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name="\"Model\"")
    private String model;

    @Column(name="\"Name\"")
    private String name;

    @Column(name="\"Purchasing_date\"")
    private BigDecimal purchasing_date;

    public Vehicle() {
    }

    public String getModel() {
        return this.model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BigDecimal getPurchasing_date() {
        return this.purchasing_date;
    }

    public void setPurchasing_date(BigDecimal purchasing_date) {
        this.purchasing_date = purchasing_date;
    }

}