回调函数

本文探讨了编程中类A与类B互相引用的问题,通过回调函数实现类B访问类A的方法,包括静态回调、函数指针和类指针的运用,以及在实际代码中的应用实例。

一、前言

在这里插入图片描述

最近在编程过程中碰到一个问题,大概结构如下图示,类A中定义了B的实例,想在类B中访问类A,由于类A用引用了类B,类B中就不能再引用类A,否则会因相互引用而报错。

类B是一个自定义类继承自QwtPlot,由于QwtPlot不是QObject的直接子类,所以无法导入宏Q_OBJECT,所以无法在该类中使用信号槽机制。后面考虑用双继承方式,双继承方式必须将QObject写在前面,例如:

class Plot_View : public QObject, public QwtPlot
{
	Q_OBJECT
	public:
		Plot_View(QObject* parent1 = nullptr, QwtPlot* parent2 = nullptr);
};

Plot_View::Plot_View(QObject* parent1, QwtPlot* parent2) : QObject(parent1), QwtPlot(parent2)
{

}

虽然编译通过,但是程序直接中断,可能是多继承这块的知识点有欠缺,故放弃了这一方法,后来考虑采用回调函数来进行通信。


二、回调函数

2.1、注意事项

在类封装回调函数:

  • 回调函数只能是全局的或是静态的。
  • 全局函数会破坏类的封装性,故不予采用。
  • 静态函数只能访问类的静态成员,不能访问类中非静态成员

2.2、具体步骤

结构:主类引用副类,副类不能再引用主类,但是副类想访问主类

#include <QMainWindow>
#include "child_form.h"

class MainWindow : public QMainWindow
{
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    Child_Form* child_form;
};

①、主类中定义静态回调函数

static void Function(QString str); //静态回调函数

②、副类中定义函数指针类型别名

typedef void (*CALLBACK)(QString str); //定义函数指针类型别名

③、副类中定义函数指针

CALLBACK F_PTR;//函数指针

③、在主类中通过副类实例对象将回调函数的地址赋给子类中的函数指针(函数名就是函数地址、入口)

child_form->F_PTR = Function; //将回调函数的地址赋给函数指针

此时副类中的函数指针就拥有了回调函数的地址,可以直接用函数指针调用回调函数

F_PTR("Hello");

但是回调函数是静态函数,只能访问静态成员,如果想访问非静态成员,还需做如下操作:

④、在主类中定义静态类指针

static MainWindow* m; //静态类指针

⑤、在主类外初始化静态类指针

MainWindow* MainWindow::m = nullptr;

⑥、在主类构造函数中将this指针赋值给静态类指针

m = this; //将this指针赋给静态指针

⑦、在静态回调函数中通过静态类指针访问非静态类成员

void MainWindow::Function(QString str)//回调函数
{
    m->ui->pushButton->setText(str);
}

2.3、完整代码

主类

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDebug>
#include "child_form.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    Child_Form* child_form;

    static void Function(QString str); //静态回调函数
    static MainWindow* m; //静态类指针

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow* MainWindow::m = nullptr;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    m = this; //将this指针赋给静态指针

    child_form = new Child_Form; //实例化
    child_form->F_PTR = Function; //将回调函数的地址赋给函数指针
    child_form->show();
}

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


void MainWindow::on_pushButton_clicked()
{

}

void MainWindow::Function(QString str)//回调函数
{
    m->ui->pushButton->setText(str);
}

副类

#ifndef CHILD_FORM_H
#define CHILD_FORM_H

#include <QWidget>

namespace Ui {
class Child_Form;
}

typedef void (*CALLBACK)(QString str); //定义函数指针类型别名

class Child_Form : public QWidget
{
    Q_OBJECT
public:
    explicit Child_Form(QWidget *parent = nullptr);
    ~Child_Form();
    bool flag;

    CALLBACK F_PTR;//函数指针

private slots:
    void on_pushButton_clicked();

private:
    Ui::Child_Form *ui;
};

#endif // CHILD_FORM_H
#include "child_form.h"
#include "ui_child_form.h"

Child_Form::Child_Form(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Child_Form)
{
    ui->setupUi(this);
    flag = false;
}

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

void Child_Form::on_pushButton_clicked()
{
    flag = !flag;
    if(flag)
        F_PTR("Hello");
    else
        F_PTR("World");
}

2.4、效果展示

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

贝勒里恩

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

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

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

打赏作者

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

抵扣说明:

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

余额充值