使用访问者模式检查派生的 class 类型?
Using visitor pattern for checking derived class type?
我正在使用访问者模式来处理很多不同的 AST 问题,事实证明这种模式非常有效。例如,我用它来检查静态类型。这在查找确切类型时效果很好,但它不适用于派生的 classes。即,如果我们有继承自 Base
的 Derived
,询问 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)
改为 return true
而不是 false
如何解决这个问题,所以我可以有效地检查 class 继承?这在 C++ 中可能吗?
你不能。原因是重载解析(和您的设计模式)。每个访问者都有两个重载,一个用于 Base&
,第二个用于 Derived&
。 LogicVisitor
使用作为模板参数传递的类型覆盖函数,因此对于 Base
它将覆盖 void visit(Base&)
.
您希望它为 Base
覆盖 void visit(Derived&)
而不是(或另外)。但这需要访问者找到从 Base
派生的每个 class,目前这是不可能的。
您可以使用 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>>;
}
我正在使用访问者模式来处理很多不同的 AST 问题,事实证明这种模式非常有效。例如,我用它来检查静态类型。这在查找确切类型时效果很好,但它不适用于派生的 classes。即,如果我们有继承自 Base
的 Derived
,询问 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)
改为 return true
而不是 false
如何解决这个问题,所以我可以有效地检查 class 继承?这在 C++ 中可能吗?
你不能。原因是重载解析(和您的设计模式)。每个访问者都有两个重载,一个用于 Base&
,第二个用于 Derived&
。 LogicVisitor
使用作为模板参数传递的类型覆盖函数,因此对于 Base
它将覆盖 void visit(Base&)
.
您希望它为 Base
覆盖 void visit(Derived&)
而不是(或另外)。但这需要访问者找到从 Base
派生的每个 class,目前这是不可能的。
您可以使用 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>>;
}