当前位置: 首页 > news >正文

突破编程_C++_设计模式(访问者模式)

1 访问者模式的基本概念

C++中的访问者模式是一种行为设计模式,它允许你在不修改类层次结构的情况下增加新的操作。这种模式将数据结构与数据操作解耦,使得操作可以独立于对象的类来定义。

访问者模式的主要组成部分包括:

(1)访问者(Visitor): 这是一个接口,它声明了一个访问操作,该操作可以被应用到所有的元素上。访问操作的具体实现在访问者的子类中完成。

(2)元素(Element): 这是一个接口,它定义了一个接受操作,该操作可以被一个访问者访问。元素接口通常有一个接受访问者作为参数的接受方法。

(3)具体元素(Concrete Element): 这是实现元素接口的具体类,它实现了接受方法,该方法将调用访问者的访问方法。

(4)对象结构(Object Structure): 这是元素的集合,它以一种合适的方式包含元素。对象结构可以是一个简单的集合,也可以是一个复杂的树形结构。

2 访问者模式的实现步骤

访问者模式的实现步骤如下:

(1)定义访问者接口:

首先,需要定义一个访问者接口,这个接口声明了所有可能应用于元素对象的操作。这些操作通常作为纯虚函数存在,具体的操作实现将由具体的访问者类来完成。

(2)定义元素接口:

接下来,定义一个元素接口,这个接口声明了一个接受方法,该方法接受一个访问者对象作为参数。元素接口中的接受方法通常是虚函数,以便在元素的具体类中实现多态性。

(3)实现具体元素类:

然后,创建实现元素接口的具体元素类。这些类将包含数据,并实现接受方法,该方法将调用访问者的访问方法。

(4)实现具体的访问者类:

接着,创建实现访问者接口的具体访问者类。这些类将包含访问元素所需的具体逻辑。当访问者的访问方法被调用时,它将针对具体的元素对象执行相应的操作。

(5)创建对象结构:

创建一个对象结构,该结构负责管理元素对象的集合。这可以是一个简单的容器,如数组或向量,也可以是一个更复杂的结构,如树或图。

(6)使用访问者模式:

最后,在客户端代码中,创建具体的访问者对象,并通过对象结构访问元素对象。当需要执行某个操作时,通过对象结构的遍历方法,将具体的访问者对象传递给每个元素对象的接受方法。元素对象的接受方法将调用访问者的访问方法,从而执行相应的操作。

如下为样例代码:

#include <iostream>  
#include <vector>  
#include <memory>  class Element;// 步骤一:定义访问者接口  
class Visitor {
public:virtual ~Visitor() = default;virtual void visit(const std::shared_ptr<Element>& element) const = 0;
};// 步骤二:定义元素接口  
class Element : public std::enable_shared_from_this<Element> {
public:virtual ~Element() = default;virtual void accept(const std::shared_ptr<Visitor>& visitor) = 0;
};// 步骤三:实现具体元素类  
class ConcreteElement : public Element {
public:void accept(const std::shared_ptr<Visitor>& visitor) override {visitor->visit(shared_from_this());}void operation() const {std::cout << "ConcreteElement operation" << std::endl;}
};// 步骤四:实现具体的访问者类  
class ConcreteVisitor : public Visitor {
public:void visit(const std::shared_ptr<Element>& element) const override {auto concreteElement = std::dynamic_pointer_cast<ConcreteElement>(element);if (concreteElement) {concreteElement->operation();std::cout << "Visited by ConcreteVisitor" << std::endl;}else {std::cout << "Element is not of type ConcreteElement" << std::endl;}}
};// 步骤五:创建对象结构  
class ObjectStructure {
public:void attach(const std::shared_ptr<Element>& element) {m_elements.push_back(element);}void detach(const std::shared_ptr<Element>& element) {auto it = std::find(m_elements.begin(), m_elements.end(), element);if (it != m_elements.end()) {m_elements.erase(it);}}void accept(const std::shared_ptr<Visitor>& visitor) const {for (const auto& element : m_elements) {element->accept(visitor);}}private:std::vector<std::shared_ptr<Element>> m_elements;
};// 步骤六:使用访问者模式  
int main() 
{// 创建对象结构并添加元素  ObjectStructure objectStructure;objectStructure.attach(std::make_shared<ConcreteElement>());// 创建访问者  std::shared_ptr<Visitor> visitor = std::make_shared<ConcreteVisitor>();// 执行访问  objectStructure.accept(visitor);return 0;
}

上面代码的输出为:

ConcreteElement operation
Visited by ConcreteVisitor

上面的代码使用了 std::shared_ptr 智能指针来管理 Visitor 和 Element 对象的生命周期。std::dynamic_pointer_cast 用于安全地执行动态类型转换,以确认 Element 指针是否可以转换为 ConcreteElement 类型。如果转换成功,则执行相应的操作。

ObjectStructure 类负责管理 Element 对象的集合,并提供 attach 和 detach 方法来添加和删除元素。accept 方法则遍历所有元素,并将访问者传递给每个元素的 accept 方法,从而执行访问操作。

在 main 函数中,创建了一个 ObjectStructure 对象,并向其添加了一个 ConcreteElement 对象。然后,创建了一个 ConcreteVisitor 对象,并通过 ObjectStructure 的 accept 方法将访问者传递给所有元素。这样,就实现了访问者模式的使用。

3 访问者模式的应用场景

C++ 访问者模式的应用场景广泛,主要适用于以下情况:

(1)双层分派场景: 访问者模式实现了一种称为“双层分派”的机制。第一层分派发生在客户端代码中,当客户端将访问者对象传递给元素对象的 accept 方法时。第二层分派发生在元素对象的 accept 方法内部,它根据访问者的类型调用相应的访问方法。这种双层分派机制使得操作可以在元素对象的上下文中执行,并且可以根据元素的类型进行不同的处理。

(2)数据结构稳定但操作易变的场景: 如果数据结构相对稳定,但需要在其上执行的操作经常变化,访问者模式可以帮助将这些操作与数据结构解耦,使得操作的变化不会影响到数据结构的定义。

(3)操作需要扩展的场景: 当需要对一个对象结构中的元素执行多种不同的、不相关的操作时,且这些操作可能会在未来发生变化或增加时,使用访问者模式非常合适。通过将操作封装在访问者中,可以在不修改元素类的情况下添加新的操作。

(4)需要对对象结构中的对象进行不同操作的场景: 当需要在运行时决定对对象结构中的哪些元素执行哪些操作时,访问者模式可以很容易地实现这种动态行为。

(5)复杂的对象结构遍历: 当需要遍历一个复杂的对象结构(如树形结构、图结构等),并对结构中的每个元素执行特定的操作时,访问者模式可以简化代码结构,使得遍历和操作逻辑更加清晰和分离。

3.1 访问者模式应用于双层分派场景

双层分派允许根据对象类型和访问者类型动态地决定执行哪个操作。以下是一个简单的游戏场景,其中游戏角色可以被不同的访问者(例如渲染器或AI处理器)访问。

首先,定义访问者接口和元素接口:

#include <iostream>  
#include <memory>  
#include <vector>  
#include <string>  class Character;// 访问者接口  
class Visitor {
public:virtual ~Visitor() = default;virtual void visit(const std::shared_ptr<Character>& character) const = 0;
};// 元素接口  
class Character : public std::enable_shared_from_this<Character> {
public:virtual ~Character() = default;virtual void accept(const std::shared_ptr<Visitor>& visitor) = 0;virtual std::string getName() const = 0;
};

接着,定义具体的游戏角色类和访问者类:

// 具体游戏角色类A  
class Warrior : public Character {
public:std::string getName() const override { return "Warrior"; }void accept(const std::shared_ptr<Visitor>& visitor) override {visitor->visit(shared_from_this());}void fight() const {std::cout << getName() << " is fighting!" << std::endl;}
};// 具体游戏角色类B  
class Mage : public Character {
public:std::string getName() const override { return "Mage"; }void accept(const std::shared_ptr<Visitor>& visitor) override {visitor->visit(shared_from_this());}void castSpell() const {std::cout << getName() << " is casting a spell!" << std::endl;}
};// 具体访问者类:渲染器  
class Renderer : public Visitor {
public:void visit(const std::shared_ptr<Character>& character) const override {std::cout << "Rendering " << character->getName() << std::endl;}
};// 具体访问者类:AI处理器  
class AIProcessor : public Visitor {
public:void visit(const std::shared_ptr<Character>& character) const override {std::cout << "Processing AI for " << character->getName() << std::endl;// 这里可以根据角色类型执行不同的AI逻辑  }
};

最后,定义一个管理游戏角色的对象结构类,并使用访问者进行双层分派:

// 对象结构类:游戏世界  
class GameWorld {
public:void addCharacter(const std::shared_ptr<Character>& character) {m_characters.push_back(character);}void render(const std::shared_ptr<Visitor>& visitor) const {for (const auto& character : m_characters) {character->accept(visitor);}}private:std::vector<std::shared_ptr<Character>> m_characters;
};int main() 
{// 创建游戏角色  auto warrior = std::make_shared<Warrior>();auto mage = std::make_shared<Mage>();// 创建游戏世界并添加角色  GameWorld gameWorld;gameWorld.addCharacter(warrior);gameWorld.addCharacter(mage);// 创建渲染器访问者  auto renderer = std::make_shared<Renderer>();// 使用渲染器访问者渲染所有角色  gameWorld.render(renderer);// 创建AI处理器访问者  auto aiProcessor = std::make_shared<AIProcessor>();// 使用AI处理器访问者处理所有角色的AI  gameWorld.render(aiProcessor);// 不需要手动释放对象,智能指针会自动处理  return 0;
}

上面代码的输出为:

Rendering Warrior
Rendering Mage
Processing AI for Warrior
Processing AI for Mage

在这个示例中,Warrior 和 Mage 类继承了 Character 接口,并实现了各自的 accept 方法和特定行为(如 fight 和 castSpell)。Renderer 和 AIProcessor 类继承了 Visitor 接口,并实现了针对 Character 的 visit 方法。

GameWorld 类管理着游戏中的角色,并提供了 render 方法,该方法接受一个 Visitor 智能指针,并使用 accept 方法触发双层分派。当调用 gameWorld.render(renderer) 时,所有角色都会被渲染器访问,并调用它们各自的 accept 方法。由于 accept 方法内部调用了 visitor->visit(shared_from_this()),这就会触发对应的 visit 方法,在这里是 Renderer 类的 visit 方法,负责渲染角色。

3.2 访问者模式应用数据结构稳定但操作易变的场景

该场景是指:对于一组稳定的数据结构(元素),在这些数据结构上执行各种易变的操作(访问者)时,每个操作可能需要访问数据结构的不同部分,并且可能以不同的方式处理这些部分。

下面是一个使用访问者模式的示例,它模拟了一个简单的形状集合,其中形状是稳定的数据结构,而不同的操作(如计算面积、周长等)是易变的访问者。

首先,定义形状接口和访问者接口:

#include <iostream>  
#include <memory>  
#include <vector>  class Visitor;// 形状接口  
class Shape : public std::enable_shared_from_this<Shape> {
public:virtual ~Shape() = default;virtual void accept(const std::shared_ptr<Visitor>& visitor) = 0;
};class Circle;
class Rectangle;// 访问者接口  
class Visitor {
public:virtual ~Visitor() = default;virtual void visit(const std::shared_ptr<Circle>& circle) const = 0;virtual void visit(const std::shared_ptr<Rectangle>& rectangle) const = 0;
};

接着,定义具体的形状类和访问者类:

// 圆形类  
class Circle : public Shape {double radius;
public:Circle(double r) : radius(r) {}void accept(const std::shared_ptr<Visitor>& visitor) override {visitor->visit(std::dynamic_pointer_cast<Circle>(shared_from_this()));}double getRadius() const { return radius; }
};// 矩形类  
class Rectangle : public Shape {double width, height;
public:Rectangle(double w, double h) : width(w), height(h) {}void accept(const std::shared_ptr<Visitor>& visitor) override {visitor->visit(std::dynamic_pointer_cast<Rectangle>(shared_from_this()));}double getWidth() const { return width; }double getHeight() const { return height; }
};// 计算面积的访问者  
class AreaVisitor : public Visitor {
public:void visit(const std::shared_ptr<Circle>& circle) const override {std::cout << "Circle area: " << 3.14159 * circle->getRadius() * circle->getRadius() << std::endl;}void visit(const std::shared_ptr<Rectangle>& rectangle) const override {std::cout << "Rectangle area: " << rectangle->getWidth() * rectangle->getHeight() << std::endl;}
};// 计算周长的访问者  
class PerimeterVisitor : public Visitor {
public:void visit(const std::shared_ptr<Circle>& circle) const override {std::cout << "Circle perimeter: " << 2 * 3.14159 * circle->getRadius() << std::endl;}void visit(const std::shared_ptr<Rectangle>& rectangle) const override {std::cout << "Rectangle perimeter: " << 2 * (rectangle->getWidth() + rectangle->getHeight()) << std::endl;}
};

最后,创建一个管理形状的对象结构类,并使用访问者进行操作:

// 对象结构类:形状集合  
class ShapeCollection {
public:void addShape(const std::shared_ptr<Shape>& shape) {m_shapes.push_back(shape);}void process(const std::shared_ptr<Visitor>& visitor) const {for (const auto& shape : m_shapes) {shape->accept(visitor);}}private:std::vector<std::shared_ptr<Shape>> m_shapes;
};int main() 
{// 创建形状  auto circle = std::make_shared<Circle>(5.0);auto rectangle = std::make_shared<Rectangle>(4.0, 6.0);// 创建形状集合并添加形状  ShapeCollection collection;collection.addShape(circle);collection.addShape(rectangle);// 创建并使用面积访问者  auto areaVisitor = std::make_shared<AreaVisitor>();collection.process(areaVisitor);// 创建并使用周长访问者  auto perimeterVisitor = std::make_shared<PerimeterVisitor>();collection.process(perimeterVisitor);// 不需要手动释放对象,智能指针会自动处理  return 0;
}

上面代码的输出为:

Circle area: 78.5397
Rectangle area: 24
Circle perimeter: 31.4159
Rectangle perimeter: 20

在这个示例中,Circle 和 Rectangle 类继承了 Shape 接口,并实现了各自的 accept 方法和特定行为(半径以及长宽)。AreaVisitor 和 PerimeterVisitor 类继承了 Visitor 接口,并实现了计算圆形面积周长以及计算矩形面积周长的 visit 方法。随后在 ShapeCollection 的 process 进行访问调用。

4 访问者模式的优点与缺点

C++ 访问者模式的优点主要包括:

(1)扩展性好: 访问者模式使得在不修改已有类的情况下,可以添加新的操作。这意味着数据结构本身保持稳定,而新的操作可以很容易地添加到系统中。

(2)操作集中管理: 访问者模式将相关的操作集中到一个访问者类中,这有助于操作的封装和复用。

(3)双分派: 访问者模式通过对象的“接受”方法和访问者的“访问”方法实现了双分派,即运行时根据对象的实际类型和访问者的类型来确定执行的操作。

(4)灵活性: 访问者模式允许我们根据需要灵活地定义不同的访问者类,实现不同的操作逻辑。

(5)符合开闭原则: 访问者模式符合开闭原则,即对扩展开放,对修改封闭。当需要添加新的操作时,我们只需要添加新的访问者类,而不需要修改已有的数据结构。

然而,C++ 访问者模式也存在一些缺点:

(1)增加复杂性: 访问者模式增加了类的数量,使得系统变得更加复杂。每个元素类都需要实现接受方法,每个访问者类都需要实现访问方法,这可能导致代码量的增加。

(2)破坏封装性: 访问者模式要求元素类暴露其内部状态给访问者类,这可能会破坏元素的封装性。如果访问者类不恰当地使用这些内部状态,可能会导致错误或不可预见的行为。

(3)类型安全: 在访问者模式中,由于访问者类需要访问元素类的内部状态,因此需要确保类型安全。否则,可能会导致运行时错误。

(4)性能开销: 由于访问者模式涉及到双分派,因此在某些情况下可能会引入额外的性能开销。

相关文章:

突破编程_C++_设计模式(访问者模式)

1 访问者模式的基本概念 C中的访问者模式是一种行为设计模式&#xff0c;它允许你在不修改类层次结构的情况下增加新的操作。这种模式将数据结构与数据操作解耦&#xff0c;使得操作可以独立于对象的类来定义。 访问者模式的主要组成部分包括&#xff1a; &#xff08;1&…...

C语言入门到精通之练习53:矩阵交换行问题(附带源码)

描述 给定一个 5*5 的矩阵&#xff08;数学上&#xff0c;一个 rc 的矩阵是一个由 r 行 c 列元素排列成的矩形阵列&#xff09;&#xff0c;将第 n 行和第 m 行交换&#xff0c;输出交换后的结果。 输入输入共 6 行&#xff0c;前 5 行为矩阵的每一行元素, 元素与元素之间以一…...

Python白练-2统计下列5行字符串中字符出现的频数

问题&#xff1a;统计下列5行字符串中字符a、c、g、t出现的频数 数据&#xff1a;data2_2&#xff1a; 1.aggcacggaaaaacgggaataacggaggaggacttggcacggcattacacggagg 2.cggaggacaaacgggatggcggtattggaggtggcggactgttcgggga 3.gggacggatacggattctggccacggacggaaaggaggacacggcg…...

深入理解DHCP服务:网络地址的自动化分配

深入理解DHCP服务&#xff1a;网络地址的自动化分配 在现代网络环境中&#xff0c;动态主机配置协议&#xff08;DHCP&#xff09; 是一个至关重要的服务&#xff0c;它允许自动分配IP地址和其他相关配置信息给网络中的设备。本文将深入探讨DHCP服务的工作原理、配置方法以及如…...

Java高级编程—泛型

文章目录 1.为什么要有泛型 (Generic)1.1 泛型的概念1.2 使用泛型后的好处 2.在集合中使用泛型3.自定义泛型结构3.1 自定义泛型类、泛型接口3.2 自定义泛型方法 4.泛型在继承上的体现5.通配符的使用5.1 基本使用5.2 有限制的通配符的使用 1.为什么要有泛型 (Generic) Java中的…...

Exam in MAC [容斥]

题意 思路 正难则反 反过来需要考虑的是&#xff1a; (1) 所有满条件一的(x,y)有多少对&#xff1a; x 0 时&#xff0c;有c1对 x 1 时&#xff0c;有c对 ...... x c 时&#xff0c;有1对 以此类推 一共有 (c2)(c1)/2 对 (2) 符合 x y ∈ S的有多少对&#xff1a…...

Java 学习和实践笔记(36):接口(interface)

面向对象的精髓&#xff0c;最能体现这一点的就是接口&#xff01; 为什么我们讨论设计模式都只针对具备了抽象能力的语言&#xff08;比如C、Java、C#等)&#xff0c;就是因为设计模式所研究的&#xff0c;实际上就是如何合理的去抽象。 接口就是一组规范&#xff0c;所有实…...

Elastic Stack--10--QueryBuilders UpdateQuery

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 QueryBuildersESUtil QueryBuilders package com.elasticsearch; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.search.Sea…...

腾讯云服务器CVM_云主机_云计算服务器_弹性云服务器

腾讯云服务器CVM提供安全可靠的弹性计算服务&#xff0c;腾讯云明星级云服务器&#xff0c;弹性计算实时扩展或缩减计算资源&#xff0c;支持包年包月、按量计费和竞价实例计费模式&#xff0c;CVM提供多种CPU、内存、硬盘和带宽可以灵活调整的实例规格&#xff0c;提供9个9的数…...

Java八股文(Spring Boot)

Java八股文のSpring Boot Spring Boot Spring Boot 什么是Spring Boot&#xff1f; Spring Boot是一个用于开发和构建微服务应用程序的框架&#xff0c;它简化了Spring应用的配置和部署。 Spring Boot的核心特性是什么&#xff1f; Spring Boot的核心特性包括自动配置、起步依…...

ts文件怎么无损转换mp4?这样设置转换模式~

TS格式&#xff08;Transport Stream&#xff09;的起源可追溯到数字电视广播领域。设计初衷是解决视频、音频等多媒体数据在传输和存储中的问题。采用一系列标准技术&#xff0c;TS格式让视频信号能够以流的形式传输&#xff0c;因此在数字电视、广播等领域得到广泛应用。 MP4…...

如何在Windows 10上打开和关闭平板模式?这里提供详细步骤

前言 默认情况下&#xff0c;当你将可翻转PC重新配置为平板模式时&#xff0c;Windows 10会自动切换到平板模式。如果你希望手动打开或关闭平板模式&#xff0c;有几种方法可以实现。​ 自动平板模式在Windows 10上如何工作 如果你使用的是二合一可翻转笔记本电脑&#xff0…...

介绍kafka核心原理及底层刷盘机制,集群分片机制,消息丢失和重复消费有对应的线上解决方案

Kafka是一个高性能、分布式、持久化的消息系统&#xff0c;它的核心原理包括发布/订阅模型、分布式日志存储和高吞吐量的数据流处理。 发布/订阅模型&#xff1a;Kafka采用发布/订阅模型&#xff0c;消息的生产者将消息发送到一个或多个主题&#xff08;Topic&#xff09;&…...

基于Python的中医药知识问答系统设计与实现

[简介] 这篇文章主要介绍了基于Python的中医药知识问答系统的设计与实现。该系统利用Python编程语言&#xff0c;结合中医药领域的知识和技术&#xff0c;实现了一个功能强大的问答系统。文章首先介绍了中医药知识的特点和传统问答系统的局限性&#xff0c;然后提出了设计思路…...

QT 如何防止 QTextEdit 自动滚动到最下方

在往QTextEdit里面append字符串时&#xff0c;如果超出其高度&#xff0c;默认会自动滚动到QTextEdit最下方。但是有些场景可能想从文本最开始的地方展示&#xff0c;那么就需要禁止自动滚动。 我们可以在append之后&#xff0c;添加如下代码&#xff1a; //设置编辑框的光标位…...

【C/C++ 学习笔记】指针

【C/C 学习笔记】指针 视频地址: Bilibili 概念 可以通过指针间接访问内存用于保存地址 使用 通过 & 可以获取数据的指针 通过 * 可以取得指针的数据 指针的数据类型就是 数据类型 * int number 10;int *p &number;// 10 cout << "number: " …...

【Node.js从基础到高级运用】十二、身份验证与授权:JWT

身份验证与授权是现代Web应用中不可或缺的部分。了解如何在Node.js应用中实施这些机制&#xff0c;将使你能够构建更安全、更可靠的应用程序。本文将引导你通过使用JWT实现用户注册、登录和权限控制的过程。 JWT&#xff08;Json Web Token&#xff09; JWT是一种用于双方之间…...

蓝桥杯刷题|01入门真题

[蓝桥杯 2020 省 AB1] 解码 题目描述 小明有一串很长的英文字母&#xff0c;可能包含大写和小写。 在这串字母中&#xff0c;有很多连续的是重复的。小明想了一个办法将这串字母表达得更短&#xff1a;将连续的几个相同字母写成字母 出现次数的形式。 例如&#xff0c;连续…...

Python Django相关解答

问题&#xff1a;什么是django&#xff1f; Django是一个开源的高级web框架&#xff0c;皆在快速开发安全可维护的网站。他鼓励快速开发&#xff0c;并遵循“don’t repeat yourself”DRY原则 Django的MTV架构是什么 Django遵循MTV(模型-模板-试图)架构模式。模型&#xff08;…...

在Linux/Ubuntu/Debian中使用7z压缩和解压文件

要在 Ubuntu 上使用 7-Zip 创建 7z 存档文件&#xff0c;你可以使用“7z”命令行工具。 操作方法如下&#xff1a; 安装 p7zip&#xff1a; 如果你尚未在 Ubuntu 系统上安装 p7zip&#xff08;7-Zip 的命令行版本&#xff09;&#xff0c;你可以使用以下命令安装它&#xff1a;…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

测试微信模版消息推送

进入“开发接口管理”--“公众平台测试账号”&#xff0c;无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息&#xff1a; 关注测试号&#xff1a;扫二维码关注测试号。 发送模版消息&#xff1a; import requests da…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error

在前端开发中&#xff0c;JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作&#xff08;如 Promise、async/await 等&#xff09;&#xff0c;开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝&#xff08;r…...

提升移动端网页调试效率:WebDebugX 与常见工具组合实践

在日常移动端开发中&#xff0c;网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时&#xff0c;开发者迫切需要一套高效、可靠且跨平台的调试方案。过去&#xff0c;我们或多或少使用过 Chrome DevTools、Remote Debug…...

【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权

摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题&#xff1a;安全。文章将详细阐述认证&#xff08;Authentication) 与授权&#xff08;Authorization的核心概念&#xff0c;对比传统 Session-Cookie 与现代 JWT&#xff08;JS…...