【Qt学习】02:信号和槽机制

news2024/9/24 15:29:26

信号和槽机制


OVERVIEW

  • 信号和槽机制
      • 一、系统自带信号与槽
      • 二、自定义信号与槽
        • 1.基本使用
          • student.cpp
          • teacher.cpp
          • widget.cpp
          • main.cpp
        • 2.信号与槽重载
          • student.cpp
          • teacher.cpp
          • widget.cpp
          • main.cpp
        • 3.信号连接信号
        • 4.Lambda表达式
        • 5.信号与槽总结

信号槽机制是 Qt 框架引以为豪的机制之一。

所谓信号槽实际就是观察者模式,将要处理的信号自己的一个函数/槽slot绑定来处理信号,当某个事件发生之后检测对象就会发出信号(无目的的广播),如果有其他对象对这个信号感兴趣就会使用connect函数进行连接。

即当信号发出时,被连接的槽函数会自动被回调。类似观察者模式:当发生了感兴趣的事件,某个操作就会被自动触发。

一、系统自带信号与槽

信号槽的优点:松散耦合,信号发送方和接收方本身是没有关联的,通过connect连接将两端耦合在一起

QPushButton * quitBtn = new QPushButton("quit",this);//创建关闭按钮
connect(quitBtn, &QPushButton::clicked, this, &QWidget::close);//信号槽使用方式

函数connect(sender, signal, receiver, slot);参数解释:

  • sender:发出信号的对象
  • signal:发送对象发出的信号
  • receiver:接收信号的对象
  • slot:接收对象在接收到信号之后所需要调用的函数(槽函数)

利用帮助文档了查找系统自带的信号和槽,在帮助文档中如按钮的点击信号输入QPushButton,首先我们可以在Contents中寻找关键字 signals信号的意思,但是我们发现并没有找到,这时候我们应该想到也许这个信号的被父类继承下来的,因此我们去他的父类QAbstractButton中就可以找到该关键字,点击signals索引到系统自带的信号有如下几个。

这里的clicked就是我们要找到,槽函数的寻找方式和信号一样,只不过他的关键字是slot。

二、自定义信号与槽

使用connect可使用系统提供的信号和槽,

但Qt的信号槽机制并不仅仅是使用系统提供那部分,其还允许开发者设计自己的信号和槽,

1.基本使用

student.cpp
#ifndef STUDENT_H
#define STUDENT_H

#include <QObject>

class Student : public QObject {
    Q_OBJECT
public:
    explicit Student(QObject *parent = nullptr);
signals:

public slots:
    //槽函数slot 返回值是void 需要声明需要实现 可以有参数(发生重载)
    void treat();
};

#endif // STUDENT_H
#include "student.h"
#include <QDebug>

Student::Student(QObject *parent) : QObject(parent) { }

void Student::treat() {
    qDebug() << "debug: receive signal. student treats teacher.";
}
teacher.cpp
#ifndef TEACHER_H
#define TEACHER_H

#include <QObject>

class Teacher : public QObject {
    Q_OBJECT
public:
    explicit Teacher(QObject *parent = nullptr);
signals:
    //信号signal 返回值是void 只需要声明不需要实现 可以有参数(发生重载)
    void hungry();
public slots:

};

#endif // TEACHER_H
#include "teacher.h"

Teacher::Teacher(QObject *parent) : QObject(parent) { }
widget.cpp
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "teacher.h"
#include "student.h"

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget {
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    void classIsOver();
private:
    Ui::Widget *ui;
    Teacher *tch;
    Student *stu;
};

#endif // WIDGET_H
#include <QPushButton>
#include <QDebug>
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
    ui->setupUi(this);
    //1.第一次绑定 使用系统自带信号与槽函数
    QPushButton *mybtn = new QPushButton("myBtn", this);
    mybtn->resize(100, 30);
    connect(mybtn, &QPushButton::clicked, this, &Widget::classIsOver);//按钮触发classIsOver函数
    //2.第二次绑定 使用自定义信号与槽函数
    tch = new Teacher(this);//初始化老师对象
    stu = new Student(this);//初始化学生对象
    connect(tch, &Teacher::hungry, stu, &Student::treat);//老师饿了时学生主动请客的connect连接
}

Widget::~Widget() {
    delete ui;
}

void Widget::classIsOver() {
    qDebug() << "debug: btn is pushed and Widget::classIsOver was called. emitting signal...";
    emit tch->hungry();//函数被调用 则触发发送老师饿了的信号
}
main.cpp
#include <QApplication>
#include "widget.h"

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

在这里插入图片描述

2.信号与槽重载

student.cpp
#ifndef STUDENT_H
#define STUDENT_H

#include <QObject>

class Student : public QObject {
    Q_OBJECT
public:
    explicit Student(QObject *parent = nullptr);
signals:

public slots:
    //槽函数slot 返回值是void 需要声明需要实现 可以有参数(发生重载)
    void treat();
    void treat(QString food);
};

#endif // STUDENT_H
#include "student.h"
#include <QDebug>

Student::Student(QObject *parent) : QObject(parent) { }

void Student::treat() {
    qDebug() << "debug: receive signal. student treats teacher.";
}

void Student::treat(QString food) {
    qDebug() << "debug: receive signal. student treats teacher with " << food.toUtf8().data();
}
teacher.cpp
#ifndef TEACHER_H
#define TEACHER_H

#include <QObject>

class Teacher : public QObject {
    Q_OBJECT
public:
    explicit Teacher(QObject *parent = nullptr);
signals:
    //信号signal 返回值是void 只需要声明不需要实现 可以有参数(发生重载)
    void hungry();
    void hungry(QString food);
public slots:

};

#endif // TEACHER_H
#include "teacher.h"

Teacher::Teacher(QObject *parent) : QObject(parent) { }
widget.cpp
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "teacher.h"
#include "student.h"

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget {
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    void classIsOver1();
    void classIsOver2();
private:
    Ui::Widget *ui;
    Teacher *tch;
    Student *stu;
};

#endif // WIDGET_H
#include <QPushButton>
#include <QDebug>
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
    ui->setupUi(this);
    //1.第一次绑定 使用系统自带信号与槽函数
    QPushButton *mybtn1 = new QPushButton("myBtn1", this);
    mybtn1->resize(100, 30);
    connect(mybtn1, &QPushButton::clicked, this, &Widget::classIsOver1);//按钮触发classIsOver函数
    QPushButton *mybtn2 = new QPushButton("myBtn2", this);
    mybtn2->move(100, 0);
    mybtn2->resize(100, 30);
    connect(mybtn2, &QPushButton::clicked, this, &Widget::classIsOver2);//按钮触发classIsOver函数

    tch = new Teacher(this);//初始化老师对象
    stu = new Student(this);//初始化学生对象
    //2.第二次绑定 使用自定义信号与槽函数
    void(Teacher::*tchsignal_)() = &Teacher::hungry;
    void(Student::*stusignal_)() = &Student::treat;
    connect(tch, tchsignal_, stu, stusignal_);//老师饿了时学生主动请客的connect连接
    //3.第三次绑定 使用自定义信号与槽函数
    //定义函数指针 用于识别重载的函数地址
    void(Teacher::*tchsignal)(QString) = &Teacher::hungry;
    void(Student::*stusignal)(QString) = &Student::treat;
    connect(tch, tchsignal, stu, stusignal);
}

Widget::~Widget() {
    delete ui;
}

void Widget::classIsOver1() {
    qDebug() << "debug: btn1 is pushed and Widget::classIsOver1 was called. emitting signal...";
    emit tch->hungry();//函数被调用 则触发发送老师饿了的信号
}

void Widget::classIsOver2() {
    qDebug() << "debug: btn2 is pushed and Widget::classIsOver2 was called. emitting signal...";
    emit tch->hungry("apple pie");
}
main.cpp
#include <QApplication>
#include "widget.h"

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

在这里插入图片描述

3.信号连接信号

之前的使用中都是利用槽函数实现的,点击btn按钮触发函数调用,函数调用后emit发出信号再触发slot槽函数,从而实现连续的效果。

也可以使用另一种方式信号触发信号完成,利用点击btn按钮的信号去触发另一个信号,

主要对widget.cpp中的内容进行修改,修改后如下:

#include <QPushButton>
#include <QDebug>
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
    ui->setupUi(this);
    //1.第一次绑定 使用系统自带信号与槽函数
    QPushButton *mybtn1 = new QPushButton("myBtn1", this);
    mybtn1->resize(100, 30);
    //connect(mybtn1, &QPushButton::clicked, this, &Widget::classIsOver1);//按钮触发classIsOver函数

    QPushButton *mybtn2 = new QPushButton("myBtn2", this);
    mybtn2->move(100, 0);
    mybtn2->resize(100, 30);
    //connect(mybtn2, &QPushButton::clicked, this, &Widget::classIsOver2);//按钮触发classIsOver函数

    tch = new Teacher(this);//初始化老师对象
    stu = new Student(this);//初始化学生对象
    //2.第二次绑定 使用自定义信号与槽函数
    void(Teacher::*tchsignal_)() = &Teacher::hungry;
    void(Student::*stusignal_)() = &Student::treat;
    connect(tch, tchsignal_, stu, stusignal_);//老师饿了时学生主动请客的connect连接
    connect(mybtn1, &QPushButton::clicked, tch, tchsignal_);//信号连接信号

    //3.第三次绑定 使用自定义信号与槽函数
    //定义函数指针 用于识别重载的函数地址
    void(Teacher::*tchsignal)(QString) = &Teacher::hungry;
    void(Student::*stusignal)(QString) = &Student::treat;
    connect(tch, tchsignal, stu, stusignal);
    //connect(mybtn2, &QPushButton::clicked, tch, tchsignal);//信号连接信号
    connect(mybtn2, &QPushButton::clicked, this, [=](){
        emit tch->hungry("apple pie");
    });
}

Widget::~Widget() {
    delete ui;
}

void Widget::classIsOver1() {
    qDebug() << "debug: btn1 is pushed and Widget::classIsOver1 was called. emitting signal...";
    emit tch->hungry();//函数被调用 则触发发送老师饿了的信号
}

void Widget::classIsOver2() {
    qDebug() << "debug: btn2 is pushed and Widget::classIsOver2 was called. emitting signal...";
    emit tch->hungry("apple pie");
}

在这里插入图片描述

btn触发信号连接信号,跳过了classIsOver函数的中间调用过程,直接实现了最终结果的输出。

4.Lambda表达式

C++11中的Lambda表达式用于定义并创建匿名的函数对象以简化编程工作,Lambda表达式的基本构成:

[capture](parameters)mutable->returnType {
	statement
}
  1. 函数对象参数;[],标识一个Lambda的开始,这部分必须存在不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义Lambda为止时Lambda所在作用范围内可见的局部变量(包括Lambda所在类的this)。函数对象参数有以下形式:

    • void,没有使用任何函数对象参数。
    • =,函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)
    • &,函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)
    • this,函数体内可以使用Lambda所在类中的成员变量
    • a,将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符
    • &a,将a按引用进行传递
    • a, &b,将a按值进行传递,b按引用进行传递。
    • =,&a, &b,除a和b按引用进行传递外,其他参数都按值进行传递。
    • &, a, b,除a和b按值进行传递外,其他参数都按引用进行传递。
  2. 操作符重载函数参数;标识重载的 () 操作符的参数,没有参数时这部分可以省略。参数可以通过按值(如:(a,b))和按引用(如:(&a,&b))两种方式进行传递

  3. 可修改标示符;mutable 声明,这部分可以省略。按值传递函数对象参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)

    QPushButton * myBtn = new QPushButton (this);
    QPushButton * myBtn2 = new QPushButton (this);
    myBtn2->move(100,100);
    int m = 10;
    
    connect(myBtn,&QPushButton::clicked,this,[m] ()mutable { m = 100 + 10; qDebug() << m; });
    connect(myBtn2,&QPushButton::clicked,this,[=] ()  { qDebug() << m; });
    qDebug() << m;
    
  4. 函数返回值;-> 返回值类型,标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。

  5. 是函数体;{},标识函数的实现这部分不能省略,但函数体可以为空。

利用Lambda表达式简化信号与槽的使用机制:利用lambda表达式实现点击按钮,关闭窗口:

QPushButton *btn = new QPushButton;
btn->setText("quit");
connect(btn, &QPushButton::clicked, this, [=](){
    this->close();
});

5.信号与槽总结

在这里插入图片描述

自定义信号槽需要注意的事项:

  1. 发送者和接收者都需要是QObject的子类(槽函数是全局函数、Lambda 表达式等无需接收者的时候除外);
  2. 自定义信号signal返回值是 void,只需要声明不需要实现,可以有参数(发生重载)
  3. 槽函数是普通的成员函数,需要声明也需要实现,会受到 public、private、protected 的影响(早期必须写到public slots作用域下)
  4. 任何成员函数、static 函数、全局函数和 Lambda 表达式都可以作为槽函数

信号与槽的连接:connect函数

  1. 一个信号可以和多个槽函数相连:如果是这种情况,这些槽会一个接一个的被调用,但是它们的调用顺序是不确定的
  2. 多个信号可以连接到一个槽:只要任意一个信号发出,这个槽就会被调用
  3. 一个信号可以连接到另外的一个信号:当第一个信号发出时第二个信号被发出,除此之外这种信号-信号的形式和信号-槽的形式没有什么区别。
  4. 信号槽要求信号和槽的参数类型对应(参数的个数信号可以多于槽函数,反之报错)
  5. 若信号和槽的参数不一致,允许的情况是,槽函数的参数可以比信号的少,即便如此,槽函数存在的那些参数的顺序也必须和信号的前面几个一致起来。这是因为可以在槽函数中选择忽略信号传来的数据(也就是槽函数的参数比信号的少)。
  6. 槽可以被取消链接:这种情况并不经常出现,因为当一个对象delete之后,Qt自动取消所有连接到这个对象上面的槽
  7. 使用Lambda 表达式:在使用 Qt 5 的时候,能够支持 Qt 5 的编译器都是支持 Lambda 表达式的,在连接信号和槽的时候,槽函数可以使用Lambda表达式的方式进行处理。

QT4版本的信号槽写法:Qt5在语法上完全兼容Qt4。

connect(tch, SIGNAL(hungry(QString)), stu, SLOT(treat(QString)));

这里使用了SIGNAL和SLOT这两个宏,将两个函数名转换成了字符串。注意到connect函数的signal和slot都是接受字符串,一旦出现连接不成功的情况,Qt4是没有编译错误的(因为一切都是字符串编译期是不检查字符串是否匹配),而是在运行时给出错误。这无疑会增加程序的不稳定性。

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

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

相关文章

Yolo系列-yolov2

YOLO-V2 更快&#xff01;更强&#xff01; YOLO-V2-BatchNormalization BatchNormalization&#xff08;批归一化&#xff09;是一个常用的深度神经网络优化技术&#xff0c;它可以将输入数据进行归一化处理&#xff0c;使得神经网络更容易进行学习。在YOLOv2中&#xff0c;B…

C++学习记录——이십칠 C++11(3)

文章目录 1、lambda1、捕捉列表2、简述C线程3、lambda对象大小 2、C线程1、整体了解2、锁1、互斥锁2、递归互斥锁3、时间控制锁4、lock_guard 3、atomic&#xff08;原子&#xff09;4、条件变量 1、lambda 在之前写排序时&#xff0c;用到过排升序&#xff0c;排降序&#xf…

leetcode438. 找到字符串中所有字母异位词(java)

滑动窗口 找到字符串中所有字母异位词滑动窗口数组优化 上期经典 找到字符串中所有字母异位词 难度 - 中等 Leetcode 438 - 找到字符串中所有字母异位词 给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词 的子串&#xff0c;返回这些子串的起始索引。不考虑答案输出…

msvcp140.dll丢失的解决方法,win10系统dll报错的解决方法

今天&#xff0c;我将为大家分享一个关于msvcp140.dll丢失的解决方法&#xff0c;特别是针对在Windows 10系统上遇到这个问题的朋友们。在开始之前&#xff0c;我想先简要介绍一下msvcp140.dll文件的作用。msvcp140.dll是Microsoft Visual C运行时库的一部分&#xff0c;它包含…

基于Java+SpringBoot+Vue前后端分离智慧图书管理系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

【【萌新的STM32学习-18 中断的基本概念3】】

萌新的STM32学习-18 中断的基本概念3 EXTI和IO映射的关系 AFIO简介&#xff08;F1&#xff09; Alternate Function IO 复用功能IO 主要用于重映射和外部中断映射配置 1.调试IO配置 来自AFIO_MAPR[26:24] , 配置JTAG/SWD的开关状态 &#xff08;这个我们并不用太过深刻的关注&…

使用实体解析和图形神经网络进行欺诈检测

图形神经网络的表示形式&#xff08;作者使用必应图像创建器生成的图像&#xff09; 一、说明 对于金融、电子商务和其他相关行业来说&#xff0c;在线欺诈是一个日益严重的问题。为了应对这种威胁&#xff0c;组织使用基于机器学习和行为分析的欺诈检测机制。这些技术能够实时…

【C++11新特性】可变参数模板

文章目录 1. 认识可变参数模板2. 可变参数模板的定义方式3. 参数包的展开方式3.1 递归展开参数包3.2 逗号表达式展开参数包 1. 认识可变参数模板 可变参数模板是C11新增的最强大的特性之一&#xff0c;它对参数高度泛化&#xff0c;能够让我们创建可以接收可变参数的函数模板和…

【SpringBoot学习笔记02】静态资源

Spring Boot 通过 MVC 的自动配置类 WebMvcAutoConfiguration 为这些 WebJars 前端资源提供了默认映射规则&#xff0c;部分源码如下。 jar包&#xff1a; JAR 文件就是 Java Archive File&#xff0c;顾名思意&#xff0c;它的应用是与 Java 息息相关的&#xff0c;是 Java 的…

springboot整合rabbitmq死信队列

springboot整合rabbitmq死信队列 什么是死信 说道死信&#xff0c;可能大部分观众大姥爷会有懵逼的想法&#xff0c;什么是死信&#xff1f;死信队列&#xff0c;俗称DLX&#xff0c;翻译过来的名称为Dead Letter Exchange 死信交换机。当消息限定时间内未被消费&#xff0c;…

编码过程中需要注意哪些安全问题?

SQL 安全 注入式&#xff08;Inject&#xff09;攻击是一类非常常见的攻击方式&#xff0c;其基本特征是程序允许攻击者将不可信的动态内容注入到程序中&#xff0c;并将其执行&#xff0c;这就可能完全改变最初预计的执行过程&#xff0c;产生恶意效果。下面是几种主要的注入…

为 Python 创建别名

有时您有自己喜欢的 Python 版本&#xff0c;并且不想在新版本到来时放弃它。 您的旧脚本可能无法在新版本的 Python 上运行&#xff0c;或者旧版本上的项目太多&#xff0c;将它们迁移到新版本是一场马拉松。 在这种情况下&#xff0c;您决定保留两个版本的 Python。 在本文中…

什么是算法?

目录 算法是指解决方案的准确而完整的描述。 1.算法的基本特征 所谓算法&#xff0c;是一组严谨地定义运算顺序的规则 并且每一个规则都是有效的&#xff0c;且是明确的 此顺序将在有限的次数下终止 什么是算法&#xff1f; 算法的4个基本特征 算法的6个基本方法 选择算…

浏览器输入一个URL之后发生了什么?

URL解析DNS解析TCP连接TSL连接HTTP请求TCP挥手接收并解析响应 URL 解析 主要分为&#xff1a; 协议&#xff0c;eg http,https域名或者ip地址&#xff0c;eg www.baidu.com 域名相对于ip地址来说&#xff0c;更方便人们记忆&#xff0c;但是实际的网络传输中使用的是ip地址 端…

Java“牵手”天猫商品快递费用API接口数据,天猫API接口申请指南

天猫平台商品快递费用接口是开放平台提供的一种API接口&#xff0c;通过调用API接口&#xff0c;开发者可以获取天猫商品的标题、价格、库存、商品快递费用&#xff0c;宝贝ID&#xff0c;发货地&#xff0c;区域ID&#xff0c;快递费用&#xff0c;月销量、总销量、库存、详情…

十几款拿来就能用的炫酷表白代码

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;小白零基础《Python入门到精通》 表白代码 1、坐我女朋友好吗&#xff0c;不同意就关机.vbs2、坐我女朋友好吗&…

订单状态定时处理、来单提醒和客户催单

一、Spring Task 1.1 基本介绍 1.2 cron表达式 cron表达式其实就是一个字符串&#xff0c;通过cron表达式可以定义任务触发的时间 构成规则&#xff1a;分为6或7个域&#xff0c;由空格分隔开&#xff0c;每个域代表一个含义 每个域的含义分别为&#xff1a;秒、分钟、小时、日…

C++|观察者模式

观察者模式&#xff1a; 定义对象间的一种一对多&#xff08;变化&#xff09;的依赖关系&#xff0c;以便当一个 对象(Subject)的状态发生改变时&#xff0c;所有依赖于它的对象都 得到通知并自动更新 动机&#xff1a; 在软件构建过程中&#xff0c;我们需要为某些对象建立…

【深度学习 | 核心概念】那些深度学习路上必经的核心概念,确定不来看看?(一)

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

基于吉萨金字塔建造算法优化的BP神经网络(预测应用) - 附代码

基于吉萨金字塔建造算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于吉萨金字塔建造算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.吉萨金字塔建造优化BP神经网络2.1 BP神经网络参数设置2.2 吉萨金字塔建造算法应用…