一、前言

最近在编程过程中碰到一个问题,大概结构如下图示,类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、效果展示


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

被折叠的 条评论
为什么被折叠?



