Qt案例 在对QGraphicsView视图修改和撤销修改图元操作时,使用命令模式实现。

当项目中有QGraphicsView视图直接修改图元的功能时,常会有Ctri+ZCtrl+Y这种执行与撤销图元修改的功能,以便于在修改图元后能够进行一个还原/执行操作,此时就适合使用命令模式设计来实现这个功能。
以下示例在WINDOWS系统,Qt Creator 5.13.1,MSCV2017 X64 Release环境实现,以及涉及QStack类的使用。

目录导读

    • 一、命令模式详解
    • 二、命令模式的应用场景
    • 二、QStack类详解
    • 三、QGraphicsView视图-修改还原-命令模式案例实现
      • 命令角色(Command) 接口实现
      • 请求者(Invoker)功能实现
      • 具体命令(ConcreteCommand)实现
        • 1. 窗体拖拽的上下左右平移命令对象
        • 2. 对场景类的缩放和放大命令
        • 3. 新增图元命令对象
        • 4. 删除图元命令对象
      • 接收者(Receiver)实现
      • 命令模式 缺点

一、命令模式详解

在诸多设计模式中,命令模式适用范围非常广泛,比如工业设计,CAD二开,流程图设计等,都经常能看到命令模式的设计模块和功能实现。
有时候在工作中为了尽快完成功能,基本都是面向过程开发,不会过多的使用一些设计模式,但是在面试中,只要工作年限有个两三年的,面试官都基本会问一句了解那些设计模式,谈谈具体的使用,无一例外!
所以日常中可以不用设计模式开发,但是不能不了解,特别是单例模式,提到的概率特别高!

命令模式是一种设计模式,它将请求或操作封装在对象中,并将这些对象传递给调用对象。该模式的意图是将请求发送者与实际执行操作的接收者解耦,使得发送者和接收者可以独立变化

在命令模式中,
主要有三个角色:

  • 命令(Command):定义了执行操作的接口,通常包含一个execute方法,用于调用具体的操作。
  • 具体命令(Concrete_Command):实现了命令接口,负责执行具体的操作。它通常包含了对接收者的引用,通过调用接收者的方法来完成请求的处理。
  • 接收者(Receiver):知道如何执行与请求相关的操作,实际执行命令的对象。

其他角色:

  • 调用者/请求者(Invoker):
    发送命令的对象,它包含了一个或多个命令对象并能触发命令的执行。调用者并不直接处理请求,而是通过将请求传递给命令对象来实现。
  • 客户端(Client):
    创建具体命令对象并设置其接收者,将命令对象交给调用者执行。

命令模式结构示意图(命令模式 | 菜鸟教程):
来自菜鸟教程-命令模式

命令模式的核心思想是将请求以命令的形式封装在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。这种设计使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。

命令模式的主要优点是降低了系统耦合度,使得请求的一方和接收的一方独立开来,可以独立变化。新的命令可以很容易添加到系统中去。但是,使用命令模式可能会导致某些系统有过多的具体命令类。

总之,命令模式是一种将请求或操作封装在对象中,并将这些对象传递给调用对象的设计模式,它使得请求的一方和接收的一方解耦,可以独立变化

文章参考:

  • 命令模式 | 菜鸟教程
  • 设计模式(行为型模式)之:命令模式(Command Pattern)
  • 【设计模式】命令模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )
  • 技术分享 | 什么是命令模式

二、命令模式的应用场景

命令模式的应用场景主要有以下几个方面:

  1. 多级撤销/重做: 如果系统需要实现多级撤销或重做操作,可以将命令对象存储在历史栈中,通过调用命令对象的undo和redo方法来实现撤销和重做。
  2. 事务处理: 借助命令模式,可以简单地实现一个具有原子事务的行为。
  3. 进度条: 如果系统需要按顺序执行一系列的命令操作,可以通过调用每个命令对象的getEstimatedDuration方法来评估执行状态并显示出合适的进度条。
  4. 网络通信: 通过网络发送命令到其他机器上运行。
  5. 日志系统: 可以将请求以命令的形式记录在日志中,方便日后审计和重放。
  6. 游戏开发: 在游戏开发中,命令模式常被用于实现游戏逻辑,如移动、攻击等。
  7. GUI开发: 在GUI开发中,命令模式可以用于实现撤销、重做等功能
  8. 自动化测试: 将测试用例封装为命令对象,方便测试的执行和管理。
  9. 批处理: 将一系列操作封装成命令对象,然后按照顺序或并行执行这些命令对象,以完成批量处理任务。
  10. 游戏AI: 在游戏AI中,可以使用命令模式来封装玩家的操作,然后由AI实体来解析和执行这些命令。
    总之,命令模式的应用场景非常广泛,只要是需要将请求或操作封装在对象中,并传递给调用对象的情况,都可以考虑使用命令模式。

应用场景说明来自于文言一心
如果工作中遇到以上应用场景示例,建议直接使用命令模式开发,别管会不会,多报错几次、多掉点头发就会了!

二、QStack类详解

在涉及到QGraphicsView视图修改图元操作,也就是 多级撤销/重做 这种应用场景,这种情况下需要一个堆栈来保存命令的多个对象,并且这个堆栈必须符合 后进先出 的特点,这样才能保证最后一次修改的功能最先被还原的。

QStack(Qt Stack)是一个来自于Qt框架的容器类,类似于C++标准库中的std::stackQStack容器是一种后进先出(LIFO)的数据结构,即最后一个进入堆栈的元素将最先被移除。QStack继承了QVector,所以它拥有QVector的所有功能,同时提供了堆栈的特定操作。
具体关于QStack 内容建议参考:
Qt QStack 详解:从底层原理到高级用法
描述的相当详细,老厉害了!

三、QGraphicsView视图-修改还原-命令模式案例实现

QGraphicsView视图对图元进行一个增加、删除、改变大小、移动图元等一系列操作时,使用命令模式执行/撤销修改动作命令,也就是常说的修改还原功能。

命令角色(Command) 接口实现

在操作图元时,增加、删除、改变大小、移动图元等就是一个个命令,而这些命令只有两个相同的动作,撤销命令执行命令
所以声明一个通用的 Command 接口类,

#include <QObject>
/// <summary>
/// 定义一个命令角色。一般是一个接口,为所有的命令对象声明一个接口,规范将要进行的命令操作。Command
/// 命令角色(Command): 定义命令的接口,声明执行的方法。这是一个抽象类。
/// </summary>
class Command : public QObject
{Q_OBJECT
public:explicit Command(QObject *parent = nullptr);virtual ~Command(){delete this;}////// \brief 执行命令///virtual void execute() const=0; //MSCV写法 如果加上const 就必须赋值////// \brief 撤销命令///virtual void undo() const=0;////// \brief 是否更新数据///是否需要刷新数据///用于一些操作需要更新数据源的实现/// 当前用处不大 如果涉及到数据的交互此时就需要,此处只是给个示范/// \returnvirtual bool   isrefresh_data() const{return false;}};

需要注意的是:
在MSCV编译器中,无论是否添加const ,纯虚函数一定要加 =0,否则编译不通过。
如:virtual void undo() const=0;或者virtual void undo() =0;
而在Mingw编译器中不加。

请求者(Invoker)功能实现

请求者角色(Invoker):要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。 这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
这个类一般包含在QGraphicsView类的属性中,用于存储增加、删除、改变大小、移动图元等一系列命令对象。

Invoker_Command.h 头文件

#include <QObject>
#include <QWidget>
#include <QStack>
#include <QObject>
#include <QWidget>
#include <QMessageBox>
#include "command.h"
/// <summary>
/// 请求者角色(Invoker):要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。
/// 这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
///
/// 持有一个命令对象,有一个行动方法,在某个时间点调用命令对象的 execute() 方法,将请求付诸实行。
/// </summary>class Invoker_Command:public QObject
{Q_OBJECT
public:Invoker_Command(QObject *parent = nullptr);///撤销队列 先进后出QStack<Command*>* undoStack = new QStack<Command*>();///执行队列 先进后出QStack<Command*>* redoStack = new QStack<Command*>();///插入命令角色void SetCommad(Command* _com);////// \brief 撤销动作///void UndoStack();////// \brief 执行动作///void RedoStack();////// \brief 清除所有队列///void clearall();signals:///发送撤销和还原的缓存数量 用于界面上使用,///甚至可以扩展为选定某一端前还原,部分CAD软件软件就有这种功能void stack_count(int undocount,int redocount);///数据刷新,修改界面一些属性void data_update();
};

Invoker_Command.cpp 头文件

#include "invoker_command.h"
#include <QDebug>
Invoker_Command::Invoker_Command(QObject *parent):QObject(parent)
{}void Invoker_Command::SetCommad(Command* _com)
{redoStack->clear();undoStack->push(_com);if(_com->isrefresh_data())emit data_update();emit stack_count(undoStack->count(),redoStack->count());
}void Invoker_Command::UndoStack()
{if (undoStack->count() == 0){QMessageBox::information((QWidget *)this->parent(),tr("提示"),tr("无可撤销项!"));return;}Command* com = undoStack->pop();com->undo();if(com->isrefresh_data())emit data_update();redoStack->push(com);emit stack_count(undoStack->count(),redoStack->count());
}void Invoker_Command::RedoStack()
{if (redoStack->count() == 0){QMessageBox::information((QWidget *)this->parent(),tr("提示"),tr("无可执行项!"));return;}Command* com = redoStack->pop();com->execute();if(com->isrefresh_data())emit data_update();undoStack->push(com);emit stack_count(undoStack->count(),redoStack->count());
}void Invoker_Command::clearall()
{redoStack->clear();undoStack->clear();emit stack_count(undoStack->count(),redoStack->count());
}

注意: 在添加一个命令对象时,需要清空可执行队列,否则会造成数据混乱。

具体命令(ConcreteCommand)实现

1. 窗体拖拽的上下左右平移命令对象

视窗显示内容的切换,实际就是两个的点之间的视窗移动,所以这里只需要记录前后两个基准点就行;
Order_View_Move.h

/窗体拖拽的上下左右平移 命令对象
/ 实际上是两个的点之间的视窗移动
class Order_View_Move:public Command
{Q_OBJECT
public:explicit Order_View_Move(QPointF _oldpos,QPointF _newpos,QObject *parent = nullptr);~Order_View_Move() Q_DECL_OVERRIDE {}//////  执行命令///void execute() const Q_DECL_OVERRIDE ;//////  撤销命令///void undo() const Q_DECL_OVERRIDE ;
public:bool isrefresh_data() const Q_DECL_OVERRIDE{return  false;}
private:QPointF Oldpos;QPointF Newpos;
};

Order_View_Move.cpp

Order_View_Move::Order_View_Move(QPointF _oldpos,QPointF _newpos,QObject *parent ):Command(parent),Oldpos(_oldpos),Newpos(_newpos)
{}void Order_View_Move::execute() const
{if(this->parent()!=nullptr){//QGraphicsViewRefactor 继承的 QGraphicsView ,重构类QGraphicsViewRefactor* view=qobject_cast<QGraphicsViewRefactor*>(this->parent());if(view!=nullptr ){QPointF disPointF =Newpos - Oldpos ;//调整位置view->scene()->setSceneRect( view->scene()->sceneRect().x()-disPointF.x(),view->scene()->sceneRect().y()-disPointF.y(),view->scene()->sceneRect().width(),view->scene()->sceneRect().height());view->scene()->update();}}
}
void Order_View_Move::undo() const
{if(this->parent()!=nullptr){QGraphicsViewRefactor* view=qobject_cast<QGraphicsViewRefactor*>(this->parent());if(view!=nullptr ){QPointF disPointF =Oldpos - Newpos ;//调整位置view->scene()->setSceneRect( view->scene()->sceneRect().x()-disPointF.x(),view->scene()->sceneRect().y()-disPointF.y(),view->scene()->sceneRect().width(),view->scene()->sceneRect().height());view->scene()->update();}}
}
2. 对场景类的缩放和放大命令

QGraphicsScene 场景类放大缩小需要保存三个参数;
int Delta; 判断放大还是缩小
double mom; 放大缩小倍数
QPointF Pos; 放大缩小的基准点
Order_View_Scale.h

/ <summary>
/ 命令对象
/ 对场景类的 缩放 和 放大
/ <summary>
class  Order_View_Scale:public Command
{Q_OBJECT
public:explicit Order_View_Scale(int _delta,double _mom,QPointF _Pos,QObject *parent = nullptr);~Order_View_Scale() Q_DECL_OVERRIDE {}//////  执行命令///void execute() const Q_DECL_OVERRIDE;//////  撤销命令///void undo() const Q_DECL_OVERRIDE;
private:int Delta;double mom;QPointF Pos;public:bool isrefresh_data() const Q_DECL_OVERRIDE{return  false;}
};

Order_View_Scale.cpp

Order_View_Scale::Order_View_Scale(int _delta,double _mom,QPointF _Pos,QObject *parent):Command(parent),Delta(_delta),mom(_mom),Pos(_Pos)
{
}void Order_View_Scale::execute() const
{if(this->parent()!=nullptr){QGraphicsViewRefactor* ride=qobject_cast<QGraphicsViewRefactor*>(this->parent());if(Delta>0){ride->scale_Sum=ride->scale_Sum*mom;ride->Setwheelscale(mom,mom,Pos);emit ride->Scale_Sum_Change(ride->scale_Sum);}else{ride->scale_Sum=ride->scale_Sum/mom;ride->Setwheelscale(1.0 / mom, 1.0 / mom,Pos);emit ride->Scale_Sum_Change(ride->scale_Sum);}}
}void Order_View_Scale::undo() const
{if(this->parent()!=nullptr){QGraphicsViewRefactor* ride=qobject_cast<QGraphicsViewRefactor*>(this->parent());if(!(Delta>0)){ride->scale_Sum=ride->scale_Sum*mom;ride->Setwheelscale(mom,mom,Pos);emit ride->Scale_Sum_Change(ride->scale_Sum);}else{ride->scale_Sum=ride->scale_Sum/mom;ride->Setwheelscale(1.0 / mom, 1.0 / mom,Pos);emit ride->Scale_Sum_Change(ride->scale_Sum);}}
}
3. 新增图元命令对象

新增图元执行动作就是将图元加进QGraphicsScene 场景类 中,撤销动作就是将新增图元从QGraphicsScene 场景类 中删除。
同时使用 QList<QGraphicsItem*> AddtoItems;保存图元数据。
Order_Append_FlowItem.h

/ <summary>
/ 命令对象
/ 各種图元的新增
/ <summary>
class  Order_Append_FlowItem:public Command
{Q_OBJECT
public:explicit Order_Append_FlowItem(QList<QGraphicsItem*> _AddtoItems,QObject *parent = nullptr);~Order_Append_FlowItem() Q_DECL_OVERRIDE {}//////  执行命令///void execute() const Q_DECL_OVERRIDE;//////  撤销命令///void undo() const Q_DECL_OVERRIDE;
private:QList<QGraphicsItem*> AddtoItems;public:bool isrefresh_data() const Q_DECL_OVERRIDE{return  true;}
};

Order_Append_FlowItem.cpp


Order_Append_FlowItem::Order_Append_FlowItem(QList<QGraphicsItem*> _AddtoItems,QObject *parent):Command(parent),AddtoItems(_AddtoItems)
{}void Order_Append_FlowItem::execute() const
{if(this->parent()!=nullptr){QGraphicsViewRefactor* ride=qobject_cast<QGraphicsViewRefactor*>(this->parent());for(QGraphicsItem* item:qAsConst(AddtoItems)){if(item->type()==QGraphicsFlowTextItem::Type)ride->m_scene->Correlation_Text.append(qgraphicsitem_cast<QGraphicsFlowTextItem*>(item));if(item->type()==QGraphicsConnectingLineItem::Type)ride->m_scene->ConnectLints.append(qgraphicsitem_cast<QGraphicsConnectingLineItem*>(item));ride->m_scene->addItem(item);}}
}void Order_Append_FlowItem::undo() const
{if(this->parent()!=nullptr){QGraphicsViewRefactor* ride=qobject_cast<QGraphicsViewRefactor*>(this->parent());for(QGraphicsItem* item:qAsConst(AddtoItems)){if(item->type()==QGraphicsFlowTextItem::Type)ride->m_scene->Correlation_Text.removeAll(qgraphicsitem_cast<QGraphicsFlowTextItem*>(item));if(item->type()==QGraphicsConnectingLineItem::Type)ride->m_scene->ConnectLints.removeAll(qgraphicsitem_cast<QGraphicsConnectingLineItem*>(item));ride->m_scene->removeItem(item);}}
}
4. 删除图元命令对象

删除图元对象,就是与新增图元对象命令执行与撤销的动作相反,所以这里直接继承了
Order_Append_FlowItem 新增图元命令对象而不是 Command 对象;

Order_Delete_FlowItem.h


/ <summary>
/ 命令对象
/ 图元对象的删除
/ <summary>
class Order_Delete_FlowItem:public Order_Append_FlowItem
{Q_OBJECT
public:explicit Order_Delete_FlowItem(QList<QGraphicsItem*> _AddtoItems,QObject *parent = nullptr);~Order_Delete_FlowItem() Q_DECL_OVERRIDE {}//////  执行命令///void execute() const Q_DECL_OVERRIDE;//////  撤销命令///void undo() const Q_DECL_OVERRIDE;
private:QList<QGraphicsItem*> AddtoItems;public:bool isrefresh_data() const Q_DECL_OVERRIDE{return  true;}
};

Order_Delete_FlowItem.cpp

Order_Delete_FlowItem::Order_Delete_FlowItem(QList<QGraphicsItem*> _AddtoItems,QObject *parent):Order_Append_FlowItem(_AddtoItems,parent),AddtoItems(_AddtoItems)
{}void Order_Delete_FlowItem::execute() const
{Order_Append_FlowItem::undo();
}void Order_Delete_FlowItem::undo() const
{Order_Append_FlowItem::execute();
}

接收者(Receiver)实现

知道如何执行与请求相关的操作,实际执行命令的对象就是接收者
在这个案例中通过重构QGraphicsView类,监控键盘事件【Ctrl+Z与Ctrl+Y 】来执行 请求者(Invoker_Command) 的函数,请求者(Invoker_Command) 将请求传递给 命令对象QGraphicsView类就是接受者,也是客户端(Client)

命令模式 缺点

扩展命令会导致类的数量增加 , 增加了系统实现的复杂程度 ,需要针对每个命令都要开发一个与之对应的命令类 ;在这个示例中包括修改图元,新增图元,删除图元都需要创建一系列的命令类,在实际开发中这种命令操作只会更多!!!

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

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

相关文章

echarts step line

https://ppchart.com/#/ <template><div class"c-box" ref"jsEchart"></div> </template><script> import * as $echarts from echarts // 事件处理函数 export default {props: {// 需要传递的数据data: {type: Array,defa…

字符串匹配算法(z函数模版)来自灵神。

一个字符串s求出s的z[i]&#xff0c;z[i]表示以s[i:n]这一段和s[0:n]的从前往后的连续相等字母个数。 比如 abacaba,z[2] (acaba与abacaba比较) 1。

SpringBoot整合Flowable最新教程(一)Flowable介绍

一、Flowable 入门介绍 代码实现文章&#xff1a;SpringBoot整合Flowable最新教程&#xff08;二&#xff09; 官网地址&#xff1a;https://www.flowable.org/   Flowable6.3中文教程&#xff1a;中文教程地址   可以在官网下载对应的jar包在本地部署运行&#xff0c;官方…

【IC设计】Windows下基于IDEA的Chisel环境安装教程(图文并茂)

Chisel环境安装教程 第一步 安装jdk&#xff0c;配置环境变量第二步 安装sbt&#xff0c;不用配置环境变量第三步 安装idea社区版第四步 离线安装scala的idea插件第五步 配置sbt换源1.切换目录2.创建repositories文件3.配置sbtconfig.txt文件 第六步 使用chisel-tutorial工程运…

CISCRISC? CPU架构有哪些? x86 ARM?

编者按&#xff1a;鉴于笔者水平有限&#xff0c;文中难免有不当之处&#xff0c;还请各位读者海涵。 是为序 我猜&#xff0c;常年混迹CSDN的同学应该不会没听说过CPU吧&#xff1f; 但你真的了解CPU吗&#xff1f;那笔者问你CPU有哪些架构呢&#xff1f; 如果你对你的答案…

FCIS 2023:洞悉网络安全新态势,引领创新防护未来

随着网络技术的飞速发展&#xff0c;网络安全问题日益凸显&#xff0c;成为全球共同关注的焦点。在这样的背景下&#xff0c;FCIS 2023网络安全创新大会应运而生&#xff0c;旨在汇聚业界精英&#xff0c;共同探讨网络安全领域的最新动态、创新技术和解决方案。 本文将从大会的…

JVM 性能调优 - Java 中的四种引用(4)

为什么会有四种引用 我们先回顾下在 Java 虚拟机内存体系(1) 中提到了的垃圾回收算法 1、引用计数法 原理:给对象添加一个引用计数器,每当有一个地方引用它,计数器的值就加一。每当有一个引用失效,计数器的值就减一。当计数器值为零时,这个对象被认为没有其他对象引用,…

JDK和Spring的SPI机制原理分析

目录 一、JDK 二、Spring框架介绍 三、SPI机制原理 一、JDK JDK是Java Development Kit的缩写&#xff0c;是Java开发工具包的意思。它是用于开发Java应用程序和运行Java程序的软件包。JDK包含了Java编译器&#xff08;javac&#xff09;和Java虚拟机&#xff08;JVM&#…

【快速上手QT】01-QWidgetQMainWindow QT中的窗口

总所周知&#xff0c;QT是一个跨平台的C图形用户界面应用程序开发框架。它既可以开发GUI程序&#xff0c;也可用于开发非GUI程序&#xff0c;当然我们用到QT就是要做GUI的&#xff0c;所以我们快速上手QT的第一篇博文就讲QT的界面窗口。 我用的IDE是VS2019&#xff0c;使用QTc…

【NodeJS】005- MongoDB数据库

1.简介 1.1 Mongodb 是什么 MongoDB 是一个基于分布式文件存储的数据库&#xff0c;官方地址 https://www.mongodb.com/ 1.2 数据库是什么 数据库&#xff08;DataBase&#xff09;是按照数据结构来组织、存储和管理数据的 应用程序 1.3 数据库的作用 数据库的主要作用就是…

Python实现排序算法

目录 一&#xff1a;快速排序 二&#xff1a;合并排序 三&#xff1a;冒泡排序 四&#xff1a;插入排序 五&#xff1a;选择排序 一&#xff1a;快速排序 def quicksort(arr): if len(arr) < 1: return arr pivot arr[len(arr) // 2] le…

Vu3中使用h函数

Vu3中使用h函数 h函数优缺点h函数介绍使用 h函数优缺点 h函数介绍 格式 h函数接受三个参数 依次是创建的节点,节点属性,节点内容 优点: 跳过了模板编译,性能高 缺点: 学习成本略高 使用 <template><div><div>h函数</div><table border"1…

【 BUUCTFmisc--爱因斯坦】

这题比较简单&#xff0c;but 对于macOS 的一个 bug 是无法右键查看图片的详细备注&#xff0c;这题就是例子&#xff0c;导致隐藏的密码看不见 Windows 可以看到。具体解决办法是用 exiftool 工具 brew install exiftool exiftool -verbose image.jpg 找到 XPComment 栏&am…

搭建自己的私服 maven 仓库

申明&#xff1a;本文章所使用docker-compose配置文件纯属学习运用&#xff0c;非商用如有雷同请联系本人协调处理。 一、配置docker-compose.yml文件 # 指定docker-compose的版本 version: 3 services: nexus: container_name: nexus_container image: sonatype/nex…

智能指针——浅析

智能指针 本人不才&#xff0c;只能将智能指针介绍一下&#xff0c;无法结合线程进行深入探索 介绍及作用 在异常产生进行跳转时&#xff0c;通过栈帧回收进行内存释放&#xff0c;防止内存泄漏 基于RAII思想可以创建出只能指针 RAII(Resource Acquisition Is Initializatio…

Nicn的刷题日常之 有序序列判断

目录 1.题目描述 描述 输入描述&#xff1a; 输出描述&#xff1a; 示例1 示例2 示例3 2.解题 1.题目描述 描述 输入一个整数序列&#xff0c;判断是否是有序序列&#xff0c;有序&#xff0c;指序列中的整数从小到大排序或者从大到小排序(相同元素也视为有序)。 数据…

ROM/FLASH/RAM

ROM (Read Only Memory)程序存储器: 不能擦除&#xff0c;用于存储各种固化程序和数据&#xff0c;在单片机中用来存储程序数据及常量数据或变量数据&#xff0c;凡是c文件及h文件中所有代码、全局变量、局部变量、存储在ROM中 FLASH 存储器&#xff1a; Flash 存储器&#xf…

素数取りゲーム(线性筛、连续异或、博弈论

小结博弈论题型素数的特性连续异或 代码 题目&#xff1a;素数取りゲーム 临摹的题解&#xff1a;AT_ttpc2019d题解 这题真的看题解都断断续续看了两天才看懂这一个题解 : ( 小结 本题一下遇到了我好多没了解过的点&#xff0c;博弈论、素数的一些特性&#xff0c;连续异或的…

Python中的while循环,知其然知其所以然

文章目录 while循环结构1.用循环打印1 ~ 100步骤解析2. 1 ~ 100的累加和3.死循环1. 用死循环的方法实现 1 ~ 100累加和 4. 单向循环(1)打印 一行十个小星星*(2)通过打印一个变量的形式,展现一行十个小星星(3)一行十个换色的星星 ★☆★☆★☆★☆★☆(4)用一个循环,打印十行十列…

Zookeeper相关面试准备问题

Zookeeper介绍 Zookeeper从设计模式角度来理解&#xff0c;是一个基于观察者模式设计的分布式服务管理框架&#xff0c;它负责存储和管理大家都关心的数据&#xff0c;然后接受观察者的注册&#xff0c;一旦这些数据的状态发生了变化&#xff0c;Zookeeper就负责通知已经在Zoo…