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

news2024/11/15 4:35:16

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

  • GPT给出的答案
  • 寻找灵感
    • 前置声明Element层次的实例
    • Visitor interface的声明
    • Element interface的声明
    • Element实际类的声明及实现
    • 实现一个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的方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/798849.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

05. 容器资源管理

目录 1、前言 2、CGroup 2.1、是否开启CGroup 2.2、Linux CGroup限制资源能使用 2.2.1、创建一个demo 2.2.2、CGroup限制CPU使用 2.3、Linux CGroup限制内存使用 2.4、Linux CGroup限制IO 3、Docker对资源的管理 3.1、Docker对CPU的限制 3.1.1、构建一个镜像 3.1.2…

C语言入门篇(八)

前言   本篇分享的是部分操作符的概念与用法&#xff0c;从经典例题入手&#xff0c;带你快速了解和掌握。   收录专栏&#xff1a;浅谈C语言 操作符详解上 1. 操作符分类2. 算术操作符3. 移位操作符3.1 左移操作符3.2 右移操作符 4. 位操作符5. 赋值操作符6. 单目操作符6.…

Pytest常用的命令行

查看Pytest所有的命令行 Pytest -h 结果&#xff1a; 我们使用pytest时&#xff0c;忘记了会有哪些命令行&#xff0c;或是忘记哪个命令行怎么用&#xff0c;可以进行查看下。 执行参数 命令行参数 (1)--collect-only&#xff0c;打印出具体的执行从目录到用例执行的具体显…

is与==的区别

是比较运算符&#xff0c;用于比较两个值是否相等&#xff0c;结果返回布尔类型True或False is操作符是比较值所在的内存地址是否相同&#xff0c;结果返回布尔类型True或False aList [a,b,c] bList [a,b,c] # True print(aList bList) # False print(aList is bList)# 12…

【计算机网络】应用层协议 -- 安全的HTTPS协议

文章目录 1. 认识HTTPS2. 使用HTTPS加密的必要性3. 常见的加密方式3.1 对称加密3.2 非对称加密3.3 非对称加密对称加密 4. 引入CA证书4.1 CA认证4.2 数据签名4.3 非对称机密对称加密证书认证4.4 常见问题 5. 总结 1. 认识HTTPS HTTPS全称为 Hyper Text Tranfer Protocol over …

Java---第八章(字符串-----String,StringBuilder 和 StringBuffer)

Java---第八章 字符串String字符串的常用方法StringBuilder和StringBuffer常用方法 对比String 和StringBuilder 和 StringBuffer 字符串 String 特性&#xff1a; String 类位于java.lang包中&#xff0c;无需引入&#xff0c;可直接使用String 类是由final修饰的&#xff…

【cpolar内网穿透工具】

文章目录 cpolar内网穿透工具.md概述什么是cpolar&#xff1f;cpolar可以用在哪些场景&#xff1f; 1. 注册cpolar帐号1.1 访问官网站点&#xff1a;[https://www.cpolar.com](https://link.zhihu.com/?targethttps%3A//www.cpolar.com/) 1.2 注册帐号 2. 下载Windows版本cpol…

SpringBoot使用Redis对用户IP进行接口限流

使用接口限流的主要目的在于提高系统的稳定性&#xff0c;防止接口被恶意打击&#xff08;短时间内大量请求&#xff09;。 一、创建限流注解 引入redis依赖 <!--redis--><dependency><groupId>org.springframework.boot</groupId><artifactId&g…

RK3399平台开发系列讲解(内核调试篇)Valgrind 内存调试与性能分析

🚀返回专栏总目录 文章目录 一、为什么要学会Valgrind二、什么是内存泄露三、Valgrind的移植四、Valgrind相关参数沉淀、分享、成长,让自己和他人都能有所收获!😄 📢Valgrind 是一个开源的内存调试和性能分析工具,用于帮助开发者找出程序中的内存错误,如内存泄漏、使…

Ansys 光学解决方案在 A/VMR 中的应用 | 以Apple Vision Pro 为例(1)

说明 苹果公司于近期在 WWDC23 上发布了其第一代空间计算设备 Apple Vision Pro。作为一款跨世代的融合现实产品&#xff0c;Apple Vision Pro 融合了业界尖端的光学技术以实现最佳的用户体验。在这个系列的文章中&#xff0c;我们将以 Apple Vision Pro 中的各项光学应用为引子…

获奖!CFS十二届财经峰会,群硕持续耕耘数字化科技沃土

7月26-27日&#xff0c;CFS2023第十二届财经峰会暨2023可持续商业大会&#xff0c;于北京成功举办。在这场中国经济影响力思想盛会上&#xff0c;群硕获评2023数字化转型推动力奖。 ## 开拓创新&#xff0c;屡获殊荣 CFS财经峰会设立于2012年&#xff0c;是国内众多财经及大众…

【 Python 全栈开发 - 人工智能篇 - 45 】决策树与随机森林

文章目录 一、概念与原理1.1 决策树1.1.1 概念1.1.2 原理特征选择分割方法 1.1.3 优点与缺点1.1.4 Python常用决策树算法 1.2 随机森林1.2.1 概念1.2.2 原理1.2.3 优点与缺点1.2.4 Python常用随机森林算法 1.3 决策树与随机森林的比较1.3.1 相同之处1.3.2 不同之处 二、决策树算…

苍穹外卖Day01项目日志

1.软件开发流程和人员分工是怎样的&#xff1f; 软件开发流程 一个软件是怎么被开发出来的&#xff1f; 需求分析 先得知道软件定位人群、用户群体、有什么功能、要实现什么效果等。 需要得到需求规格说明书、产品原型。 需求规格说明书 其中前后端工程师要关注的就是产品原…

C# 继承,封装,多态等知识点

一&#xff1a;面向对象的三大特征&#xff1a;继承性&#xff0c;封装性&#xff0c;多态性 1&#xff1a;继承性&#xff1a;继承主要描述是类与类之间的关系&#xff0c;通过继承可以在无需重新编写原有的类的情况下&#xff0c;对原有的类的功能进行扩展。 2&#xff1a;封…

【Lua学习笔记】Lua进阶——协程

文章目录 协程协程的定义和调度StatusRunning 协程 协程是一种并发操作&#xff0c;相比于线程&#xff0c;线程在执行时往往是并行的&#xff0c;并且线程在创建销毁执行时极其消耗资源&#xff0c;并且过长的执行时间会造成主进程阻塞。而协程可以以并发时轮值时间片来执行&…

法大大携手盘子女人坊,以数字化唤醒国风摄影新体验

第三方数据显示&#xff0c;目前&#xff0c;我国共有163万家摄影相关企业&#xff0c;有约1900个从事摄影相关业务的品牌&#xff0c;且预计到2025年艺术摄影市场规模将达到7063.18亿元。艺术摄影行业作为在时代进步、科技发展以及人民生活水平提高的推动下逐渐发展起来的行业…

flutter:角标

角标应该非常常见了&#xff0c;以小说app为例&#xff0c;通常会在小说封面的右上角上显示当前未读的章数。 badges 简介 Flutter的badges库是一个用于创建徽章组件的开源库。它提供了简单易用的API&#xff0c;使开发者可以轻松地在Flutter应用程序中添加徽章效果。 官方文…

day42-Live User Filter(实时用户过滤器)

50 天学习 50 个项目 - HTMLCSS and JavaScript day42-Live User Filter&#xff08;实时用户过滤器&#xff09; 效果 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport…

【深度学习】【三维重建】windows11环境配置tiny-cuda-nn详细教程

【深度学习】【三维重建】windows11环境配置tiny-cuda-nn详细教程 文章目录 【深度学习】【三维重建】windows11环境配置tiny-cuda-nn详细教程前言确定版本对应关系源码编译安装tiny-cuda-nn总结 前言 本人windows11下使用【Instant Neural Surface Reconstruction】算法时需要…

饱和(非饱和)激活函数

1.什么是饱和&#xff08;非饱和&#xff09;激活函数 若h(x)满足&#xff1a;&#xff0c;则h(x)称为饱和激活函数&#xff0c;例如sigmoid和tanh&#xff0c;否则为非饱和激活函数&#xff0c;例如Relu及其变体。 2.非饱和激活函数的优势有两点 能解决所谓的“梯度消失”问…