includes with Visitor Pattern 怎么写? [简单示例]
How to write includes with Visitor Pattern? [Simple Example]
我似乎无法弄清楚如何用这个简单的例子来编写访问者模式的包含。无论我做什么,我总是以循环依赖告终,但没有其他方法是有意义的。
另外,我为不同的 header 守卫(pragma vs. #ifndef)道歉,我正在测试 #pragma out 并且还没有更新文件。
Client.cpp
#include "OneVisitor.h"
#include "DataStructure.h"
int main (int argc, char * argv [])
{
OneVisitor v;
DataStructure d;
}
DataStructure.h
#ifndef _DATA_STRUCTURE_H_
#define _DATA_STRUCTURE_H_
#include "ElementA.h"
class DataStructure {
public:
DataStructure (Visitor & v)
{
std::cout << "ACCEPTS";
a->accept(v);
};
private:
ElementA * a;
};
#endif
Element.h
#ifndef _ELEMENT_H_
#define _ELEMENT_H_
#include "Visitor.h"
#include <iostream>
class Element {
public:
virtual void accept (Visitor & v) = 0;
void talk ()
{
std::cout << "ELEMENT TALKING";
};
};
#endif
ElementA.h
#pragma once
#include "Element.h"
#include "Visitor.h"
class ElementA : public Element {
public:
virtual void accept (Visitor & v) override
{
v.Visit(*this);
};
void talk ()
{
std::cout << "ELEMENT A TALKING";
};
};
Visitor.h
#ifndef _VISITOR_H_
#define _VISITOR_H_
#include "ElementA.h"
class Visitor {
public:
virtual void Visit (ElementA & a) = 0;
};
#endif
一个Visitor.h
#ifndef _ONE_VISITOR_H_
#define _ONE_VISITOR_H_
#include "Visitor.h"
class OneVisitor : public Visitor {
public:
virtual void Visit (ElementA & a) override
{
a.talk();
};
};
#endif
当我 运行 执行此操作时,我在 Element.h、ElementA.h、ElementB.h 中收到错误“访客尚未声明”。我怎样才能在这些 类 中定义访问者而不导致循环依赖?
访问者是一个非常抽象的概念,在这种情况下将其模板化是有意义的。使用模板可以让我们摆脱循环依赖,并大大简化事情。
// Visitor.hpp
#pragma once
template<class T>
class Visitor {
public:
virtual void visit(T& item) = 0;
virtual ~Visitor() = default;
};
现在,如果您想要 Element
的访问者,您可以使用 Visitor<Element>
:
// Element.hpp
#pragma once
#include "Visitor.hpp"
#include <iostream>
class Element
{
public:
virtual void accept(Visitor<Element>& v)
{
v.visit(*this);
}
virtual void talk() {
std::cout << "Element talking!\n";
}
virtual ~Element() = default;
};
既然有了这些东西,我们还可以写一个将lambdas转换成访问者的函数:
template<class T, class Func>
struct FunctionVisitor : public Visitor<T> {
Func func;
FunctionVisitor() = default;
FunctionVisitor(FunctionVisitor const&) = default;
FunctionVisitor(FunctionVisitor&&) = default;
FunctionVisitor(Func const& func)
: func(func)
{
}
void visit(T& item) override {
func(item);
}
};
template<class T, class Func>
FunctionVisitor<T, Func> makeVisitor(Func const& f) {
return FunctionVisitor<T, Func>(f);
}
汇集一切
这让我们可以写出像这样的漂亮代码:
#include "Element.hpp"
#include "Visitor.hpp"
#include <vector>
class ElemA : public Element {
public:
void talk() override {
std::cout << "ElemA talking!\n";
}
};
class ElemB : public Element {
public:
void talk() override {
std::cout << "ElemB talking!\n";
}
};
class ElemC : public Element {
public:
void talk() override {
std::cout << "ElemC talking!\n";
}
};
void visitAll(std::vector<Element*>& elements, Visitor<Element>& visitor) {
for(auto e : elements) {
e.accept(visitor);
}
}
int main() {
std::vector<Element*> elements {
new ElemA(),
new ElemB(),
new ElemC()
};
auto talk = [](Element& e) { e.talk(); };
visitAll(elements, makeVisitor<Element>(talk));
}
通过在 Visitor.h
中使用 class ElementA;
的前向声明
#ifndef _VISITOR_H_
#define _VISITOR_H_
// Just use a forward declaration of the class ElementA;
// NOTE1: The include of ElementA.h is not needed anymore.
// NOTE2: The visitor.h doesn't need to know what is defined
// in ElementA, only your .cpp needs, this is how forward
// declaration works.
class ElementA;
class Visitor {
public:
virtual void Visit (ElementA & a) = 0;
};
#endif
我似乎无法弄清楚如何用这个简单的例子来编写访问者模式的包含。无论我做什么,我总是以循环依赖告终,但没有其他方法是有意义的。
另外,我为不同的 header 守卫(pragma vs. #ifndef)道歉,我正在测试 #pragma out 并且还没有更新文件。
Client.cpp
#include "OneVisitor.h"
#include "DataStructure.h"
int main (int argc, char * argv [])
{
OneVisitor v;
DataStructure d;
}
DataStructure.h
#ifndef _DATA_STRUCTURE_H_
#define _DATA_STRUCTURE_H_
#include "ElementA.h"
class DataStructure {
public:
DataStructure (Visitor & v)
{
std::cout << "ACCEPTS";
a->accept(v);
};
private:
ElementA * a;
};
#endif
Element.h
#ifndef _ELEMENT_H_
#define _ELEMENT_H_
#include "Visitor.h"
#include <iostream>
class Element {
public:
virtual void accept (Visitor & v) = 0;
void talk ()
{
std::cout << "ELEMENT TALKING";
};
};
#endif
ElementA.h
#pragma once
#include "Element.h"
#include "Visitor.h"
class ElementA : public Element {
public:
virtual void accept (Visitor & v) override
{
v.Visit(*this);
};
void talk ()
{
std::cout << "ELEMENT A TALKING";
};
};
Visitor.h
#ifndef _VISITOR_H_
#define _VISITOR_H_
#include "ElementA.h"
class Visitor {
public:
virtual void Visit (ElementA & a) = 0;
};
#endif
一个Visitor.h
#ifndef _ONE_VISITOR_H_
#define _ONE_VISITOR_H_
#include "Visitor.h"
class OneVisitor : public Visitor {
public:
virtual void Visit (ElementA & a) override
{
a.talk();
};
};
#endif
当我 运行 执行此操作时,我在 Element.h、ElementA.h、ElementB.h 中收到错误“访客尚未声明”。我怎样才能在这些 类 中定义访问者而不导致循环依赖?
访问者是一个非常抽象的概念,在这种情况下将其模板化是有意义的。使用模板可以让我们摆脱循环依赖,并大大简化事情。
// Visitor.hpp
#pragma once
template<class T>
class Visitor {
public:
virtual void visit(T& item) = 0;
virtual ~Visitor() = default;
};
现在,如果您想要 Element
的访问者,您可以使用 Visitor<Element>
:
// Element.hpp
#pragma once
#include "Visitor.hpp"
#include <iostream>
class Element
{
public:
virtual void accept(Visitor<Element>& v)
{
v.visit(*this);
}
virtual void talk() {
std::cout << "Element talking!\n";
}
virtual ~Element() = default;
};
既然有了这些东西,我们还可以写一个将lambdas转换成访问者的函数:
template<class T, class Func>
struct FunctionVisitor : public Visitor<T> {
Func func;
FunctionVisitor() = default;
FunctionVisitor(FunctionVisitor const&) = default;
FunctionVisitor(FunctionVisitor&&) = default;
FunctionVisitor(Func const& func)
: func(func)
{
}
void visit(T& item) override {
func(item);
}
};
template<class T, class Func>
FunctionVisitor<T, Func> makeVisitor(Func const& f) {
return FunctionVisitor<T, Func>(f);
}
汇集一切
这让我们可以写出像这样的漂亮代码:
#include "Element.hpp"
#include "Visitor.hpp"
#include <vector>
class ElemA : public Element {
public:
void talk() override {
std::cout << "ElemA talking!\n";
}
};
class ElemB : public Element {
public:
void talk() override {
std::cout << "ElemB talking!\n";
}
};
class ElemC : public Element {
public:
void talk() override {
std::cout << "ElemC talking!\n";
}
};
void visitAll(std::vector<Element*>& elements, Visitor<Element>& visitor) {
for(auto e : elements) {
e.accept(visitor);
}
}
int main() {
std::vector<Element*> elements {
new ElemA(),
new ElemB(),
new ElemC()
};
auto talk = [](Element& e) { e.talk(); };
visitAll(elements, makeVisitor<Element>(talk));
}
通过在 Visitor.h
中使用class ElementA;
的前向声明
#ifndef _VISITOR_H_
#define _VISITOR_H_
// Just use a forward declaration of the class ElementA;
// NOTE1: The include of ElementA.h is not needed anymore.
// NOTE2: The visitor.h doesn't need to know what is defined
// in ElementA, only your .cpp needs, this is how forward
// declaration works.
class ElementA;
class Visitor {
public:
virtual void Visit (ElementA & a) = 0;
};
#endif