Visitor设计模式访问元素方法的问题

针对C++来说,若要实现Visitor设计模式,则会面临循环声明问题。

Element接口的声明中,需要Visitor的声明;Visitor接口需要Element……若均使用include宏则会导致至少一方无定义,进一步导致“不完全类型”错误。
但如果按照常规,仅在Visitor的声明上方采用单行声明方式添加Element实例的声明,就无法调用各个Element内部的特有方法了。

GPT给出的答案

#include <iostream>

using namespace std;

class Employee;
class HourlyEmployee;

class IVisitor {
public:
    virtual void Visit(HourlyEmployee&) = 0;
};

class Employee {
public:
    virtual void Accept(IVisitor& visitor) = 0;
};

class HourlyEmployee : public Employee {
public:
    void Accept(IVisitor& visitor) override {
        visitor.Visit(*this);
    }
    int HourlyMethod() {
        return 0;
    }
};

class PayrollVisitor : public IVisitor {
public:
    void Visit(HourlyEmployee& employee) override {
        cout << employee.HourlyMethod() << endl;
    }
};

int main() {
    HourlyEmployee hourly_employee;
    PayrollVisitor payroll_visitor;

    hourly_employee.Accept(payroll_visitor);
}

源码存在一些问题,已修改,这个文件是可以正常编译的。

寻找灵感

从整个源码结构来看,按顺序分为四个部分

前置声明Element层次的实例

在这里插入图片描述
这一部分是为了让Visitor接口能正确声明

Visitor interface的声明

C++中不存在接口的概念,用抽象类模拟。(也就是带有纯虚函数)
在这里插入图片描述

Element interface的声明

在这里插入图片描述

Element实际类的声明及实现

在这里插入图片描述
当然在实际项目中,会把声明和定义分开。

实现一个Visitor

在这里插入图片描述

客户端代码

在这里插入图片描述

实战

基于上面的分析,我们可以将整个实现放在不同文件中。
目录结构:
在这里插入图片描述
Nodes.h中,声明Element层次

#pragma once

#include "Visitor.h"

class Base
{
public:
	virtual void accept(Visitor& v) = 0;
};

class ClassA
	:public Base
{
public:
	ClassA() {}
	void accept(Visitor& v) override;
	int getid();
};

class ClassB
	:public Base
{
public:
	ClassB() {}
	void accept(Visitor& v) override;
	int getidd();
};

注意:在Element层次的头文件中include Visitor接口的声明

Nodes.cpp中,实现这些Element

#include "Nodes.h"

void ClassA::accept(Visitor& v)
{
	v.visit(*this);
}

void ClassB::accept(Visitor& v)
{
	v.visit(*this);
}

int ClassA::getid()
{
	return 1;
}

int ClassB::getidd()
{
	return 2;
}

Visitor.h中,声明Visitor接口,并在接口前前置声明Element实际类

#pragma once

#include <iostream>
using namespace std;

class ClassA;
class ClassB;

class Visitor
{
public:
	virtual void visit(ClassA& a) = 0;
	virtual void visit(ClassB& b) = 0;
};

注意:不要用包含的方式,要直接声明

另起一个文件,用来声明具体的Visitor:
RealVisitor.h

#pragma once

#include "Visitor.h"

class RealVisitor
	: public Visitor
{
public:
	void visit(ClassA& a) override;
	void visit(ClassB& b) override;
};

RealVisitor.cpp实现它:

#include "RealVisitor.h"
#include "Nodes.h"

void RealVisitor::visit(ClassA& a)
{
	cout << "a\n";
	cout << "aaa:" << a.getid() << endl;
}

void RealVisitor::visit(ClassB& b)
{
	cout << "b\n";
	cout << "bbb:" << b.getidd() << endl;
}

注意:实现前务必在cpp文件前方采用include的方式包含Element具体类声明
因为实现Visitor的时候需要调用每个具体类的方法

主函数:main.cpp

#include "Nodes.h"
#include "RealVisitor.h"

int main()
{
	ClassA a;
	ClassB b;
	RealVisitor v;
	a.accept(v);
	b.accept(v);

	Base &c=a;
	c.accept(v);
}

测试结果

a
aaa:1
b
bbb:2
a
aaa:1

可以看见,即使以Base类的身份调用accept,利用双重分发机制,也可以正确地调用Visitor的正确处理方法;Visitor的方法也可以正确地调用Element的方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dtsroy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值